Description
Description
There is currently no way to truly make constructor parameters optional forcing workarounds like this:
class DataTransferObject
{
final public function __construct(array $data)
{
foreach ($data as $key => $val) {
$this->{$key} = $val; // allows us to skip properties but throws an error in read only classes.
}
}
}
class OtherClass extends DataTransferObject {
public string $id;
public string $name;
// ... etc
}
The use case for this is the fact that we need to allow properties to be uninitialized for a GraphQL like situation.
You cant use fn arguments because that forces you to have a default value to be optional.
Null is considered a real value in the database and many other aspects of the code and is different from a "missing value".
Uninitialized vars are easily automatically ignored with for each loops and thus avoids a great deal of code needed to simply not return the keys you never asked for in an API response. Related data for things you didnt ask for are not fetched from the database, data calls return only the relevant data AS the property name they will be assigned to in the class making all of this incredibly streamlined.
The only thing thats missing is immutability and adding readonly will prevent the constructor form working.
Getters with setters would defeat the purpose, and copying the same code to hundreds of classes is far from ideal.
Traits can work for reusable code but the base class will still have to enforce some kind of check to make sure that every child class is using the trait. (this is going to be my current work around after damianwadley pointed this out below).
It would be great if there was some way to explicitly indicate an optional parameter without assuming a default value for a nice clean readonly class that allows properties to not have a value.
Like so:
readonly class OtherClass extends DataTransferObject {
public function __construct(
public string $id = uninitialized,
public string $name = uninitialized,
) {}
}
new OtherClass( ...$data );
Or perhaps introduce an optional
keyword in front of the param, but I think uninitialized as a keyword would potentially become useful for other senarios.