Returning NULL with return type declarations

Compizfox picture Compizfox · Feb 2, 2016 · Viewed 7.9k times · Source

I was refactoring a codebase for use with PHP7, particularly implementing scalar type hints and return type hints, when I encountered an problem.

I have a class with some properties, one of which an id. This id is not mandatory (you can construct an object without setting the id). When creating a new object of this class you don't set the id, and it gets an id as soon as it is inserted into the db (by a separate mapper class).

This mapper class needs to check if the object already exists in the db, and it does this by checking if the id is set:

if(empty($exampleObject->getId())) {
    // Insert object
} else {
    // Update object
}

I was applying return type hints to every function in my codebase, and the problem is that the function getId() can't return NULL if I enforce an int return type. It TypeErrors, even without having strict typing enabled:

Fatal error: Uncaught TypeError: Return value of ExampleClass::getId() must be of the type integer, null returned

I considered not setting a return type hint for this getter, but I then realised the problem is probably not the return type hinting, but the fact that I'm using mixed return types. I remember reading somewhere that using mixed return types is a bad thing, but I'm not sure how to tackle this without using mixed return types. I could:

  • Throw an exception in the getter, and design the check in the mapper class so that it catches that exception.
  • Catch the TypeError exception, and use that to indicate the id is not set.
  • Make the id property public, so I can call isset directly on that.
  • Add a different method hasId() return isset($this->id)

Frankly, don't really like any of these solutions, and I was wondering if there's a better option. What's the best practise for cases like this?

Also, shouldn't I only get a TypeError if I have strict typing enabled? I thought PHP7 defaulted to "weak type hints".

Answer

Andrea picture Andrea · Feb 3, 2016

PHP 7.1 added nullable types, where you put a question mark before the type name to mark the return type as accepting both that type and null:

public function getId(): ?int {
    /* … */
}

If you're still on PHP 7.0, I suggest omitting the type declaration and using a docblock.