Consider the following user class:
<?php
class User
{
private string $name;
public function getName(): string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
}
$user = new User();
We would like to get the $name
property of object $user
. However, the $name
property has not always been set. If we run $user->getName()
and the $name
property has not been set, then we get the following warning:
PHP Warning: Uncaught Error: Typed property User::$name must not be accessed before initialization
How can we call $user->getName()
without running into errors?
Use __isset
?
Should we use the __isset
magic method? For example, we could add the following __isset
method to the class:
public function __isset($name): bool {
return isset($this->$name);
}
And then, from outside the class, we could run:
if (isset($user->name)) {
// $user->getName() can now be called
}
However, it seems odd that our code would contain $user->name
knowing in advance that the $name
property is private. Also, since we call the $name
property often, we would be adding this if
statement in numerous (perhaps hundreds of) places in our code.
Default $name
to be null?
For example, we could update our class:
class User
{
private ?string $name = null;
public function getName(): ?string
{
return $this->name;
}
// ...
}
And then, from outside the class, we could run:
if (isset($user->getName())) {
// Do stuff ...
}
However, it seems odd that $name
would default to null
since null
is not a valid value for someone’s name. An "uninitialized" value seems more appropriate. And, we would again need to add numerous if
statements around our code.
Any suggestions or feedback would be very much appreciated. Thank you.
3
Answers
Four ways come to my mind:
getName()
Use a non-typed property, or initialize it in the constructor, or with the declaration of the property.
The whole point or a typed property is to avoid comparison with null (well, one of the points). Also null is not a string. So using a null/or-string type defeates the whole point more or less – you may just as well use a non-typed property instead.
You have the wrong frame of mind imho. In the OOP paradigm, it’s your responsibility to initialize your objects properly, as opposed to asking "are my objects initialized propery?" after instantiation.
So the answer is: initialize it properly, or declare a default value.
GLHF
Avoiding the use of conditional checks throughout your system could be difficult as it appears your system expects
valid
values but these are not always available and, depending on how the places yourgetters
are called use the return value.If your
User
is open to some modification, then you could as you’ve suggested make certain properties nullable or initialize them with suitable values (null
,empty
, whatever works for your business/use case). As Nigel Ren has mentioned in his comment anull
value can be perfectly valid depending on the scenario (although it might not be ideal).The following might be helpful to you, although it doesn’t entirely mitigate the requirement to perform conditional checks. It does provide some (arguably) easier helper methods for performing such checks and returning some default values.
The output of the above would be: