Nette PHP Generator přináší sílu PHP 8.4

před 3 dny od David Grudl  

Property hooks a asymetrická viditelnost v PHP 8.4 představují velký skok v objektově orientovaném programování – konečně můžeme zapomenout na neohrabané gettery a settery. Nette PHP Generator přichází s podporou těchto novinek zároveň s vydáním PHP 8.4. A nabízí intuitivní způsob, jak tyto moderní features využít ve vašem kódu.

Zbavte se getterů a setterů

Představte si, že vytváříte třídu Person a chcete validovat věk. Dříve by váš kód musel vypadat nějak takto:

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;
    }
}

S property hooks je kód elegantnější a přehlednější:

class Person
{
    public int $age {
        set {
            if ($value < 0) {
                throw new \InvalidArgumentException;
            }
            $this->age = $value;
        }
    }
}

Vygenerovat tento kód je s Nette PhpGenerator snadné. Stačí využít novou metodu addHook():

$class = new ClassType('Person');
$class->addProperty('age')
	->setType('int')
	->addHook('set')
		->setBody(<<<'PHP'
			if ($value < 0) {
				throw new InvalidArgumentException;
			}
			$this->age = $value;
			PHP);

Nabízí se také použít zkrácenou syntaxi:

$class = new ClassType('Person');
$class->addProperty('age')
	->setType('int')
	->addHook('set', '$value >= 0 ? $value : throw new \\InvalidArgumentException');

Která vygeneruje „short-setter“:

class Person
{
	public int $age {
		set => $value >= 0 ? $value : throw new \InvalidArgumentException;
	}
}

Property v rozhraních a abstraktních třídách

Ano, konečně lze v PHP používat properties v rozhraních a abstraktních třídách. Nejprve vytvoříme vlastnost v rozhraní:

$interface = new Nette\PhpGenerator\InterfaceType('Named');
$interface->addProperty('name')
    ->setType('string')
    ->addHook('get'); // Vyžaduje pouze čtení

Vygeneruje:

interface Named
{
    public string $name { get; }
}

Toto je příklad abstraktní třídy, která kombinuje abstraktní setter a konkrétní getter:

$abstract = new Nette\PhpGenerator\ClassType('Person')
	->setAbstract();
$prop = $abstract->addProperty('email')
	->setType('string')
	->setAbstract();       // Abstraktní property
$prop->addHook('set')      // Abstraktní setter
	->setAbstract();
$prop->addHook('get', '$this->email');  // Konkrétní getter

Vygeneruje:

abstract class Person
{
	public string $email {
		set;
		get => $this->email;
	}
}

A nakonec implementující třída. Tady nám pomůže ClassManipulator:

$class = new ClassType('Employee');

// Pomocí manipulátoru implementujeme Person a Named
$manipulator = new Nette\PhpGenerator\ClassManipulator($class);
$manipulator->implement('Person'); // přidá property email
$manipulator->implement('Named'); // přidá property name

// Dodáme implementaci abstraktní property z Person
$class->getProperty('email')
	->addHook('set')
		->setBody(<<<'PHP'
			if (!Nette\Utils\Validators::isEmail($value)) {
				throw new InvalidArgumentException;
			}
			$this->email = $value;
			PHP);

echo $class;

Vygeneruje:

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;
}

Asymetrická viditelnost: přesná kontrola přístupu

Asymetrická viditelnost přináší do PHP jemnější kontrolu nad tím, kdo může číst a kdo zapisovat do vlastností objektu.

Viditelnost lze nastavit buď pomocí metody setVisibility() se dvěma parametry, nebo pomocí setPublic(), setProtected() nebo setPrivate() s parametrem mode, který určuje, zda se viditelnost vztahuje ke čtení nebo zápisu vlastnosti. Výchozí režim je 'get'.

$class = new Nette\PhpGenerator\ClassType('Demo');

$class->addProperty('name')
    ->setType('string')
    ->setVisibility('public', 'private'); // public pro čtení, private pro zápis

$class->addProperty('id')
    ->setType('int')
    ->setProtected('set'); // protected pro zápis

Vygeneruje:

class Demo
{
    public private(set) string $name;

    protected(set) int $id;
}

Asymetrickou viditelnost můžete efektivně kombinovat s property hooks a využít v hierarchii tříd.


Všechny tyto novinky jsou plně podporovány v metodách ClassLike::from() pro generování z existujících tříd a ClassLike::fromCode() pro načítání ze zdrojových souborů. Pro správnou funkci fromCode() je vyžadován balíček nikic/php-parser minimálně ve verzi 5.3.1.

Podpora těchto revolučních features přichází s verzí Nette PHP Generator 4.1.7.