Testing if a class attribute is initialized with PHP
Published on 2021-12-23 • Modified on 2021-12-23
We test if a class attribute is initialized with PHP in this snippet. It may not be obvious; we all know how to test if a variable is set with the isset()
function, but the check is not the same. We can also use the isset()
function in this case! We can also use reflection with the ReflectionProperty::isInitialized()
function. PHPStan isn't happy with this code and reports: Dead catch - Error is never thrown in the try block
because of the try/catch
block.
<?php
declare(strict_types=1);
namespace App\Controller\Snippet;
use App\Samples\ProductSample;
/**
* I am using a PHP trait to isolate each snippet in a file.
* This code should be called from a Symfony controller extending AbstractController (as of Symfony 4.2)
* or Symfony\Bundle\FrameworkBundle\Controller\Controller (Symfony <= 4.1).
* Services are injected in the main controller constructor.
*/
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;
}
}
Run this snippet ≪ this.showUnitTest ? this.trans.hide_unit_test : this.trans.show_unit_test ≫ More on Stackoverflow Read the doc More on the 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);
}
}
}