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 out code.
Any suggestions or feedback would be very much appreciated. Thank you.
CodePudding user response:
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.
In php, what is a good way to determine whether private property is set?
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
CodePudding user response:
Four ways come to my mind:
- Initialize $name upon definition
- Force the constructor to initialize $name
- Check within
getName()
- Add a helper method
class User
{
// either pre-initialize
private string $name = '';
// or enforce setting by constructor
public function __construct(string $name = '')
{
$this->name = $name;
}
public function getName(): string
{
// or check within getName(), null-coalescing operator added as suggested by Robert in a comment
return $this->name ?? '';
}
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
// or add a public helper function
public function isNameSet(): bool
{
return (isset($this->name));
}
}
$user = new User();
if ($user->isNameSet()) {
// Do things
}
CodePudding user response:
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 your getters
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 a null
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.
class User
{
private ?string $name = null;
private ?string $nickname = '';
private ?string $city = 'New York';
public function getName()
{
return $this->name !== null && !empty($this->name)
? $this->name
: "Not Provided";
}
public function getNickName()
{
return $this->nickname !== null && !empty($this->nickname)
? $this->nickname
: "Not Provided";
}
public function getCity()
{
return $this->city !== null && !empty($this->city)
? $this->city
: "Not Provided";
}
public function uninitialised()
{
$uninitialized = [];
foreach (get_object_vars($this) as $property => $value) {
if (!isset($value) || empty($value)) {
$uninitialized[] = $property;
}
}
return $uninitialized;
}
public function checkForUninitialised(array $properties)
{
return array_intersect($properties, $this->uninitialised());
}
}
$user = new User();
var_dump($user->uninitialised());
echo PHP_EOL;
var_dump(
$user->checkForUninitialised(
['name', 'nickname', 'city'],
$user->uninitialised()
)
);
The output of the above would be:
array(2) {
[0]=>
string(4) "name"
[1]=>
string(8) "nickname"
}
array(2) {
[0]=>
string(4) "name"
[1]=>
string(8) "nickname"
}
CodePudding user response:
In PHP, one way to determine whether a private property of an object is set is to use the isset() function. This function checks if a variable is set and is not NULL.
For example, consider the following class with a private property $name:
class Person {
private $name;
public function __construct($name) {
$this->name = $name;
}
}
$person = new Person('John');
To check if the $name property is set, you could use the following code:
if (isset($person->name)) {
// The $name property is set
} else {
// The $name property is not set
}
Keep in mind that, because the $name property is private, you will not be able to access it directly from outside the class. Instead, you will need to use a public method to get or set the value of the property.
For example, you could add a getName() method to the Person class to allow you to retrieve the value of the $name property:
class Person {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
$person = new Person('John');
if (isset($person->getName())) {
// The $name property is set
} else {
// The $name property is not set
}