Type hinting for properties in PHP 7?
PHP 7.4 will support typed properties like so:
class Person
{
public string $name;
public DateTimeImmutable $dateOfBirth;
}
PHP 7.3 and earlier do not support this, but there are some alternatives.
You can make a private property which is accessible only through getters and setters which have type declarations:
class Person
{
private $name;
public function getName(): string {
return $this->name;
}
public function setName(string $newName) {
$this->name = $newName;
}
}
You can also make a public property and use a docblock to provide type information to people reading the code and using an IDE, but this provides no runtime type-checking:
class Person
{
/**
* @var string
*/
public $name;
}
And indeed, you can combine getters and setters and a docblock.
If you're more adventurous, you could make a fake property with the __get
, __set
, __isset
and __unset
magic methods, and check the types yourself. I'm not sure if I'd recommend it, though.
Type hinting in PHP 7 - array of objects
It's not included.
If it's not included, do you have Any clue why it was not included when type hinting was added?
With the current array implementation, it would require checking all array elements at runtime, because the array itself contains no type information.
It has actually already been proposed for PHP 5.6 but rejected: RFC "arrayof" - interestingly not because of performance issues which turned out to be neglible, but because there was no agreement in how exactly it should be implemented. There was also the objection that it is incomplete without scalar type hints. If you are interested in the whole discussion, read it in the mailing list archive.
IMHO array type hints would provide most benefit together with typed arrays, and I'd love to see them implemented.
So maybe it's about time for a new RFC and to reopen this discussion.
Partial Workaround:
you can type hint variadic arguments and thus write the signature as
function findUserByAge(int $age, User ...$users) : array
Usage:
findUserByAge(15, ...$userInput);
In this call, the argument $userInput
will be "unpacked" into single variables, and in the method itself "packed" back into an array $users
. Each item is validated to be of type User
. $userInput
can also be an iterator, it will be converted to an array.
Unfortunately there is no similar workaround for return types, and you can only use it for the last argument.
Nullable string type hinting gives syntax error in PHP 7.2
Typed properties were not included until PHP 7.4.
Is type callable supported with typed properties?
Proposal in provided link https://wiki.php.net/rfc/typed-properties has status declined.
The proposal implemented in php7.4 is here https://wiki.php.net/rfc/typed_properties_v2 and there's an explanation about callable
:
The callable type is not supported, because its behavior is context
dependent The following example illustrates the issue:class Test {
public callable $cb;
public function __construct() {
// $this->cb is callable here
$this->cb = [$this, 'method'];
}
private function method() {}
}
$obj = new Test;
// $obj->cb is NOT callable here
($obj->cb)();
This means that it is possible to write a legal value to a property
and then proceed to read an illegal value from the same property. This
fundamental problem of thecallable
pseudo-type is laid out in much
more detail in the consistent callables RFC.The recommended workaround is to instead use the
Closure
type, in
conjunction withClosure::fromCallable()
. This ensures that the
callable will remain callable independent of scope. For a discussion
of alternative ways to handle the callable issue, see the Alternatives
section.
List of all implemented proposals for php7.4 is here https://wiki.php.net/rfc#php_74.
PHP 7.4 Typed properties iteration
If you want to allow a typed attribute to be nullable you can simply add a ?
before the type and give NULL
as default value like that:
class DragonBallClass
{
public ?string $goku = NULL;
public string $bulma = 'Bulma';
public string $vegeta = 'Vegeta';
}
In this case NULL
is a perfectly legitimate value (and not a dummy value).
demo
Also without using ?
, you can always merge the class properties with the object properties lists:
class DragonBallClass
{
public string $goku;
public string $bulma = 'Bulma';
public string $vegeta = 'Vegeta';
}
$dragonBall = new DragonBallClass();
$classProperties = get_class_vars(get_class($dragonBall));
$objectProperties = get_object_vars($dragonBall);
var_dump(array_merge($classProperties, $objectProperties));
// array(3) {
// ["goku"]=>
// NULL
// ["bulma"]=>
// string(5) "Bulma"
// ["vegeta"]=>
// string(6) "Vegeta"
// }
What is the typed property for Resource
Short answer:
You can't. Sorry.
Some background:
There's an RFC here discussing the gap, but it hasn't moved since 2015: https://wiki.php.net/rfc/resource_typehint
The original RFC for scalar type hints specified that
No type declaration for resources is added, as this would prevent moving from resources to objects for existing extensions, which some have already done (e.g. GMP).
There's a comment on bug 71518 making the point that type-hinting for a resource really isn't very useful, since you'd still be able to pass in a file handle, or a GD resource, or a CURL handle, none of which do remotely the same thing. The bug itself has been suspended, so it doesn't look like this is going to be addressed any time soon.
A user-land compromise could be to write a thin object-wrapper around whichever resource type you need, and type-hint against that class instead. You still won't get typed property support for the resource on your new object, but it makes the issue less visible to the rest of your application.
Type hinting for properties in PHP 7?
PHP 7.4 will support typed properties like so:
class Person
{
public string $name;
public DateTimeImmutable $dateOfBirth;
}
PHP 7.3 and earlier do not support this, but there are some alternatives.
You can make a private property which is accessible only through getters and setters which have type declarations:
class Person
{
private $name;
public function getName(): string {
return $this->name;
}
public function setName(string $newName) {
$this->name = $newName;
}
}
You can also make a public property and use a docblock to provide type information to people reading the code and using an IDE, but this provides no runtime type-checking:
class Person
{
/**
* @var string
*/
public $name;
}
And indeed, you can combine getters and setters and a docblock.
If you're more adventurous, you could make a fake property with the __get
, __set
, __isset
and __unset
magic methods, and check the types yourself. I'm not sure if I'd recommend it, though.
Why I am suddenly getting a Typed property must not be accessed before initialization error when introducing properties type hints?
Since PHP 7.4 introduces type-hinting for properties, it is particularly important to provide valid values for all properties, so that all properties have values that match their declared types.
A property that has never been assigned doesn't have a null
value, but it is on an undefined
state, which will never match any declared type. undefined !== null
.
For the code above, if you did:
$f = new Foo(1);
$f->getVal();
You would get:
Fatal error: Uncaught Error: Typed property Foo::$val must not be accessed before initialization
Since $val
is neither string
nor null
when accessing it.
The way to get around this is to assign values to all your properties that match the declared types. You can do this either as default values for the property or during construction, depending on your preference and the type of the property.
For example, for the above one could do:
class Foo {
private int $id;
private ?string $val = null; // <-- declaring default null value for the property
private Collection $collection;
private DateTimeInterface $createdAt;
private ?DateTimeInterface $updatedAt;
public function __construct(int $id) {
// and on the constructor we set the default values for all the other
// properties, so now the instance is on a valid state
$this->id = $id;
$this->createdAt = new DateTimeImmutable();
$this->updatedAt = new DateTimeImmutable();
$this->collection = new ArrayCollection();
}
Now all properties would have a valid value and the the instance would be on a valid state.
This can hit particularly often when you are relying on values that come from the DB for entity values. E.g. auto-generated IDs, or creation and/or updated values; which often are left as a DB concern.
For auto-generated IDs, the recommended way forward is to change the type declaration to:
private ?int $id = null
For all the rest, just choose an appropriate value for the property's type.
Type hinting in class variables
PHP 7.3 and below does not support typed properties. You could only define a variable as below:
class Sandbox {
private $connection;
However, to help editors understand your code, you may use a @var
tag to document the expected type of the property:
class Sandbox {
/** @var Connectors\ISandboxConnector */
private $connection;
Update
PHP 7.4.0
Thanks @Manuel for mentioning the new update, PHP 7.4 now introduces typed properties according to PHP RFC: Typed Properties 2.0.
Property type declarations support all type declarations supported by PHP, with the exception of void
and callable
. Any class or interface name, stdClass, scalar and compound types, references to parent and own objects are also supported.
class Sandbox {
public int $id;
public string $name;
private Connectors\ISandboxConnector $connection;
}
Note: keep an eye on side effects such as uninitialised state and inheritance strict rules.
Related Topics
Laravel Change Connection Dynamically
How to Upload Large File > 5Mb in Laravel 5
Fatal Error: Uncaught Argumentcounterror: Too Few Arguments to Function
Access an Array Returned by a Function
MySQL Stored Function to Create a Slug
HTML Purifier: Removing an Element Conditionally Based on Its Attributes
How to Count the Consecutive Duplicate Values in an Array
How to Iterate by Row Through a MySQL Query in PHP
Error: Class 'Facebook\Facebooksession' Not Found with the Facebook PHP Sdk
Set Maximum Execution Time in MySQL/Php
No Database Selected - PHP & MySQL
The Ultimate Emoji Encoding Scheme
How to Remove an HTML Element Using the Domdocument Class
Is a Blob Converted Using the Current/Default Charset in MySQL
Remove Duplicates from an Array Based on Object Property
Pdo Cannot Execute Queries While Other Unbuffered Queries Are Active