Tester si un attribut d'une classe est initialisé avec PHP
Publié le 23/12/2021 • Actualisé le 23/12/2021
Dans ce bout de code, nous voyons comment tester si un attribut d'une classe PHP est initialisé. Ce n'est pas si évident qu'il n'y parait, nous savons tous comment tester l'existence d'une variable avec la fonction isset()
, mais ici le test n'est pas vraiment identique. En fait, on peut aussi utiliser isset()
dans ce cas. On peut aussi utiliser la réflexion avec la fonction ReflectionProperty::isInitialized()
. Veuillez noter que PHPStan n'est pas très content de ce code et il reporte l'erreur suivante : Dead catch - Error is never thrown in the try block
par rapport au bloc try / catch
.
<?php
declare(strict_types=1);
namespace App\Controller\Snippet;
use App\Samples\ProductSample;
/**
* J'utilise un trait PHP afin d'isoler chaque snippet dans un fichier.
* Ce code doit être apellé d'un contrôleur Symfony étendant AbstractController (depuis Symfony 4.2)
* ou Symfony\Bundle\FrameworkBundle\Controller\Controller (Symfony <= 4.1).
* Les services sont injectés dans le constructeur du contrôleur principal.
*/
trait Snippet180Trait
{
public function snippet180(): void
{
// Here is what the ProductSample class looks like
/**
* class ProductSample implements GroupSequenceProviderInterface
* {
* #[Assert\NotBlank(groups: ['foo'])]
* public string $foo;.
*/
$product = new ProductSample();
// This raises an error as $product->foo isn't initialized
try {
if ($product->foo === 'bar') {
echo '$product->foo:'.$product->foo;
}
} catch (\Error $e) {
echo $e->getMessage().PHP_EOL;
}
// With isset() ————————————————————————————————————————————————————————
if (isset($product->foo)) { // @phpstan-ignore-line
echo '$product->foo is initalized.'.PHP_EOL;
} else {
echo '$product->foo is NOT initalized.'.PHP_EOL;
}
$product->foo = 'bar';
if (isset($product->foo)) { // @phpstan-ignore-line
echo '$product->foo is initalized.'.PHP_EOL;
} else {
echo '$product->foo is NOT initalized.'.PHP_EOL;
}
// With Reflection —————————————————————————————————————————————————————
$product2 = new ProductSample();
$rp = new \ReflectionProperty(ProductSample::class, 'foo');
echo '$product2->foo initalized ? -> '.($rp->isInitialized($product2) ? 'true' : 'false').PHP_EOL;
$product2->foo = 'bar';
echo '$product2->foo initalized ? -> '.($rp->isInitialized($product2) ? 'true' : 'false').PHP_EOL;
}
}
Exécuter le snippet ≪ this.showUnitTest ? this.trans.hide_unit_test : this.trans.show_unit_test ≫ Plus sur Stackoverflow Lire la doc Plus sur le web
<?php
declare(strict_types=1);
namespace App\Tests\Integration\Controller\Snippets;
use App\Samples\ProductSample;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
/**
* @see Snippet180Trait
*/
final class Snippet180Test extends KernelTestCase
{
/**
* @see Snippet180Trait::snippet180
*/
public function testSnippet180IsSet(): void
{
$product = new ProductSample();
self::assertFalse(isset($product->foo));
$rp = new \ReflectionProperty(ProductSample::class, 'foo');
self::assertFalse($rp->isInitialized($product));
$this->expectException(\Error::class);
if ($product->foo === 'bar') {
self::assertSame('bar', $product->foo);
}
}
/**
* I have to ignore some PHPStan warnings for obvious reason.
*
* @see Snippet180Trait::snippet180
*/
public function testSnippet180IsNotSet(): void
{
$product = new ProductSample();
$product->foo = 'bar';
self::assertTrue(isset($product->foo)); // @phpstan-ignore-line
$rp = new \ReflectionProperty(ProductSample::class, 'foo');
self::assertTrue($rp->isInitialized($product));
if ($product->foo === 'bar') { // @phpstan-ignore-line
self::assertSame('bar', $product->foo);
}
}
}