Nette PHP Generator Brings the Power of PHP 8.4
Property Hooks and Asymmetric Visibility in PHP 8.4 represent a significant leap in object-oriented programming—finally, we can say goodbye to clunky getters and setters. Nette PHP Generator introduces support for these innovations alongside the release of PHP 8.4, offering an intuitive way to use these modern features in your code.
Ditch Getters and Setters
Imagine creating a Person
class and wanting to validate the age
property. Previously, your code might have looked like this:
class Person
{
private int $age;
public function setAge(int $age): void
{
if ($age < 0) {
throw new \InvalidArgumentException;
}
$this->age = $age;
}
public function getAge(): int
{
return $this->age;
}
}
With property hooks, the code becomes more elegant and readable:
class Person
{
public int $age {
set {
if ($value < 0) {
throw new \InvalidArgumentException;
}
$this->age = $value;
}
}
}
Generating this code is easy with Nette PhpGenerator. Simply use the new
addHook()
method:
$class = new ClassType('Person');
$class->addProperty('age')
->setType('int')
->addHook('set')
->setBody(<<<'PHP'
if ($value < 0) {
throw new InvalidArgumentException;
}
$this->age = $value;
PHP);
You can also use a shorthand syntax:
$class = new ClassType('Person');
$class->addProperty('age')
->setType('int')
->addHook('set', '$value >= 0 ? $value : throw new \\InvalidArgumentException');
This generates a “short-setter”:
class Person
{
public int $age {
set => $value >= 0 ? $value : throw new \InvalidArgumentException;
}
}
Properties in Interfaces and Abstract Classes
Yes, PHP now supports properties in interfaces and abstract classes. First, let’s define a property in an interface:
$interface = new Nette\PhpGenerator\InterfaceType('Named');
$interface->addProperty('name')
->setType('string')
->addHook('get'); // Read-only requirement
This generates:
interface Named
{
public string $name { get; }
}
Here’s an example of an abstract class combining an abstract setter with a concrete getter:
$abstract = new Nette\PhpGenerator\ClassType('Person')
->setAbstract();
$prop = $abstract->addProperty('email')
->setType('string')
->setAbstract(); // Abstract property
$prop->addHook('set') // Abstract setter
->setAbstract();
$prop->addHook('get', '$this->email'); // Concrete getter
This generates:
abstract class Person
{
public string $email {
set;
get => $this->email;
}
}
Finally, let’s create the implementing class. Here,
ClassManipulator
helps:
$class = new ClassType('Employee');
// Use the manipulator to implement Person and Named
$manipulator = new Nette\PhpGenerator\ClassManipulator($class);
$manipulator->implement('Person'); // Adds the email property
$manipulator->implement('Named'); // Adds the name property
// Provide the implementation for the abstract property from Person
$class->getProperty('email')
->addHook('set')
->setBody(<<<'PHP'
if (!Nette\Utils\Validators::isEmail($value)) {
throw new InvalidArgumentException;
}
$this->email = $value;
PHP);
echo $class;
This generates:
class Employee extends Person implements Named
{
public string $email {
set {
if (!Nette\Utils\Validators::isEmail($value)) {
throw new InvalidArgumentException;
}
$this->email = $value;
}
}
public string $name;
}
Asymmetric Visibility: Precise Access Control
Asymmetric visibility brings finer control over who can read and who can write object properties in PHP.
You can configure visibility using either the setVisibility()
method with two parameters or the setPublic()
,
setProtected()
, or setPrivate()
methods with a
mode
parameter specifying whether the visibility applies to reading
or writing. The default mode is 'get'
.
$class = new Nette\PhpGenerator\ClassType('Demo');
$class->addProperty('name')
->setType('string')
->setVisibility('public', 'private'); // Public for reading, private for writing
$class->addProperty('id')
->setType('int')
->setProtected('set'); // Protected for writing
This generates:
class Demo
{
public private(set) string $name;
protected(set) int $id;
}
Asymmetric visibility can be effectively combined with property hooks and used in class hierarchies.
All these features are fully supported in the methods ClassLike::from()
for generating from existing classes and ClassLike::fromCode()
for loading from source files. The fromCode()
method requires the
nikic/php-parser
package, version 5.3.1 or later.
Support for these revolutionary features is introduced in Nette PHP Generator version 4.1.7.
Sign in to submit a comment