2

One of the code style changes in our application when adopting PHP7.4 typed properties was to move from:

if (null === $object->value) { ... }

to

if (empty($object->value)) { ... }

Even when a typed property is nullable, the first if-statement will throw an Error.

The next step was on writing tests. Where using empty() on checking whether a typed property is initialized works, the PHPUnit implementation on assertEmpty crashes with the same error.

Obviously assertFalse(isset($obj->value) would work, but what assertion should get used to check if a property was not instantiated? Simplification of the test we would want:

function testInstantiatedAfterCall()
{
    $obj = new Object('http://example.com');
    $obj->changeContainer('Example Container');

    $this->assertNull($obj->value);
    // or
    $this->assertEmpty($obj->value);
}
Rvanlaak
  • 2,971
  • 20
  • 40
  • I doubt there's any (default) dedicated assertion routine for this. However, I'd advise to avoid uninitialized properties in general: always give them a value in the constructor, or define them with a default value (can be `null` if they're nullable). In other words, an object with uninitialized properties is an incomplete object. – Jeto Feb 07 '20 at 12:02
  • Also it's generally considered a bad idea to have public properties to begin with (I'm assuming these properties are, considering your samples). – Jeto Feb 07 '20 at 12:06
  • @Jeto the above is conceptual, as in PHP7.4 this also occurs when a typed property would be private and nullable: https://3v4l.org/GO48X There always will be values that are not going to get set via the constructor. The question is how to handle asserting these with PHPUnit. – Rvanlaak Feb 07 '20 at 12:52
  • "There always will be values that are not going to get set via the constructor." <- well I don't think that's a great idea. Just [set them to null](https://3v4l.org/nkSif) then. And I know that properties don't need to be public for this to occur, but since you're attempting to check them through a PHPUnit test, then they must be, and it might indicate a design issue. It's kind of another discussion though--that second comment was just a thought that I had in the process. – Jeto Feb 07 '20 at 13:02
  • 2
    FWIW I would also recommend you to initialize the properties to null. That is write `public ?Type $prop = null`. The basic premise behind uninitialized properties is that *you should not have them*. They are there to blow up your code if you accidentally forget to initialize it. Unless you have some rather specific requirements, all properties should be initialized once your constructor has finished. – NikiC Feb 07 '20 at 14:28
  • Don't use `empty()`. It had its glory in the 90s but now it brings more troubles than help. – axiac Oct 27 '21 at 17:13
  • `Unless you have some rather specific requirements, all properties should be initialized once your constructor has finished.` @NikiC that would be a great improvement for PHP's strict mode! – Rvanlaak Oct 29 '21 at 09:18

1 Answers1

0

There doesn't seem to be a built in assertion. You will have to write your own, using the ReflectionProperty::isInitialized method, like in Check in PHP 7.4 whether a property is really initialized or not.

Björn Tantau
  • 1,564
  • 14
  • 13