Hi Internals,
I would like to discuss the possibility of assigning multiple public
properties at once during the class initialization.
Currently, with constructor property promotion we've already achieved the
ability to skip a lot of boilerplate code. With property accessors (aka
hooks) we could rid of getters and setters. But often classes need
constructors only to set properties. In such cases, constructors become
redundant.
Here are a few examples:
class Person
{
public string $firstName;
public int $age;
}
$person = new Person {
firstName: "John",
age: 42
};
The initialization becomes "struct-like" but it should not affect the
current state and in general it makes code work like this:
$person = new Person();
$person->firstName = "John";
$person->age = 42;
In case if constructor exists, multiple property assignment just rewrites
values, so it could even be something like following:
class Person
{
public function __construct(
public string $firstName,
public int $age
) {
}
$person = new Person("Name", 43) {
firstName: "John",
age: 42
};
}
However, the syntax is the question and it could be done similarly to:
https://wiki.php.net/rfc/compact-object-property-assignment
Also, such "functionality" could be reused for cloning and maybe for other
appropriate cases:
$person = new Person {
firstName: "John",
age: 42
};
$person2 = clone $person {
firstName: "John Doe",
age: 43
}
Taras Chornyi
$person = new Person("Name", 43) {
firstName: "John",
age: 42
};
Hi!
You could achieve similar functionality with a simple user-land method
"assign". If you put such a method on a trait, you can use it everywhere.
See the example:
<?php
trait AssignsPropertiesValues
{
public function assign(...$props): static
{
foreach ($props as $propName => $propVal) {
$this->$propName = $propVal;
}
return $this;
}
}
class Person
{
use AssignsPropertiesValues;
public function __construct(
public string $firstName,
public int $age
) {
}
}
class Person2
{
use AssignsPropertiesValues;
public string $firstName;
public int $age;
}
class Person3
{
use AssignsPropertiesValues;
public string $firstName { set => \strtoupper($value); }
public int $age;
}
$p1 = new Person('Pig',5)->assign(firstName: 'Peppa', age: 6);
$p2 = new Person2()->assign(firstName: 'George', age: 3);
$p3 = new Person3()->assign(firstName: 'Danny', age: 7);
var_dump($p1, $p2, $p3);
Best regards,
Erick
But often classes need constructors only to set properties. In such cases, constructors become redundant.
Actually, the behavior is not the same and the constructors are not redundant.
Taking your example:
class Person
{
public string $firstName;
public int $age;
}
$person = new Person {
firstName: "John",
age: 42
};
This would allow the following:
$invalidPerson = new Person();
Now we have a person without name or age. But with constructors we
make sure that the object is always in a valid state:
class Person
{
public function __construct(public string $firstName, public int $age)
{ }
}
$validPerson = new Person('Name', 40);
$invalidPerson = new Person(); // this is impossible. every person
needs firstName and age
I just wanted to point that out. :-)