Nette Documentation Preview

syntax
Nette PhpGenerator
******************

<div class="perex">
Eszközt keres osztályok, függvények vagy teljes PHP fájlok kódjának generálásához?

- Ismeri az összes legújabb PHP funkciót (mint a property hookok, enumok, attribútumok stb.)
- Lehetővé teszi a meglévő osztályok egyszerű módosítását
- A kimeneti kód megfelel a PSR-12 / PER kódolási stílusnak
- Érett, stabil és széles körben használt könyvtár
</div>


Telepítés
---------

A könyvtárat a [Composer|best-practices:composer] segítségével töltheti le és telepítheti:

```shell
composer require nette/php-generator
```

A PHP kompatibilitást a [kompatibilitási táblázatban |#Kompatibilitási táblázat] találja.


Osztályok
---------

Kezdjük rögtön egy példával egy osztály létrehozására a [ClassType |api:Nette\PhpGenerator\ClassType] segítségével:

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

$class
	->setFinal()
	->setExtends(ParentClass::class)
	->addImplement(Countable::class)
	->addComment("Osztály leírása.\nMásodik sor\n")
	->addComment('@property-read Nette\Forms\Form $form');

// a kódot egyszerűen generálhatja stringgé alakítással vagy az echo használatával:
echo $class;
```

A következő eredményt adja vissza:

```php
/**
 * Osztály leírása
 * Második sor
 *
 * @property-read Nette\Forms\Form $form
 */
final class Demo extends ParentClass implements Countable
{
}
```

A kód generálásához használhatunk egy ún. printert is, amelyet az `echo $class`-szal ellentétben [tovább konfigurálni |#Printer és PSR megfelelőség] tudunk:

```php
$printer = new Nette\PhpGenerator\Printer;
echo $printer->printClass($class);
```

Hozzáadhatunk konstansokat ([Constant |api:Nette\PhpGenerator\Constant] osztály) és propertyket ([Property |api:Nette\PhpGenerator\Property] osztály):

```php
$class->addConstant('ID', 123)
	->setProtected() // konstansok láthatósága
	->setType('int')
	->setFinal();

$class->addProperty('items', [1, 2, 3])
	->setPrivate() // vagy setVisibility('private')
	->setStatic()
	->addComment('@var int[]');

$class->addProperty('list')
	->setType('?array')
	->setInitialized(); // kiírja '= null'
```

Generálja:

```php
final protected const int ID = 123;

/** @var int[] */
private static $items = [1, 2, 3];

public ?array $list = null;
```

És hozzáadhatunk [metódusokat |#Metódus és függvény szignatúrák]:

```php
$method = $class->addMethod('count')
	->addComment('Számold meg.')
	->setFinal()
	->setProtected()
	->setReturnType('?int') // visszatérési típusok metódusoknál
	->setBody('return count($items ?: $this->items);');

$method->addParameter('items', []) // $items = []
	->setReference()           // &$items = []
	->setType('array');        // array &$items = []
```

Az eredmény:

```php
/**
 * Számold meg.
 */
final protected function count(array &$items = []): ?int
{
	return count($items ?: $this->items);
}
```

A PHP 8.0 által bevezetett promoted paramétereket átadhatjuk a konstruktornak:

```php
$method = $class->addMethod('__construct');
$method->addPromotedParameter('name');
$method->addPromotedParameter('args', [])
	->setPrivate();
```

Az eredmény:

```php
public function __construct(
	public $name,
	private $args = [],
) {
}
```

A csak olvasható propertyket és osztályokat a `setReadOnly()` függvénnyel lehet megjelölni.

------

Ha a hozzáadott property, konstans, metódus vagy paraméter már létezik, kivétel dobódik.

Az osztály tagjait eltávolíthatjuk a `removeProperty()`, `removeConstant()`, `removeMethod()` vagy `removeParameter()` segítségével.

Az osztályhoz hozzáadhatunk meglévő `Method`, `Property` vagy `Constant` objektumokat is:

```php
$method = new Nette\PhpGenerator\Method('getHandle');
$property = new Nette\PhpGenerator\Property('handle');
$const = new Nette\PhpGenerator\Constant('ROLE');

$class = (new Nette\PhpGenerator\ClassType('Demo'))
	->addMember($method)
	->addMember($property)
	->addMember($const);
```

Klónozhatunk meglévő metódusokat, propertyket és konstansokat más néven a `cloneWithName()` segítségével:

```php
$methodCount = $class->getMethod('count');
$methodRecount = $methodCount->cloneWithName('recount');
$class->addMember($methodRecount);
```


Interfész vagy Trait
--------------------

Létrehozhat interfészeket és traitteket ([InterfaceType |api:Nette\PhpGenerator\InterfaceType] és [TraitType |api:Nette\PhpGenerator\TraitType] osztályok):

```php
$interface = new Nette\PhpGenerator\InterfaceType('MyInterface');
$trait = new Nette\PhpGenerator\TraitType('MyTrait');
```

Trait használata:

```php
$class = new Nette\PhpGenerator\ClassType('Demo');
$class->addTrait('SmartObject');
$class->addTrait('MyTrait')
	->addResolution('sayHello as protected')
	->addComment('@use MyTrait<Foo>');
echo $class;
```

Eredmény:

```php
class Demo
{
	use SmartObject;
	/** @use MyTrait<Foo> */
	use MyTrait {
		sayHello as protected;
	}
}
```


Enumok
------

A PHP 8.1 által bevezetett enumokat könnyen létrehozhatja így: ([EnumType |api:Nette\PhpGenerator\EnumType] osztály):

```php
$enum = new Nette\PhpGenerator\EnumType('Suit');
$enum->addCase('Clubs');
$enum->addCase('Diamonds');
$enum->addCase('Hearts');
$enum->addCase('Spades');

echo $enum;
```

Eredmény:

```php
enum Suit
{
	case Clubs;
	case Diamonds;
	case Hearts;
	case Spades;
}
```

Definiálhat skaláris ekvivalenseket is, és létrehozhat egy "backed" enumot:

```php
$enum->addCase('Clubs', '♣');
$enum->addCase('Diamonds', '♦');
```

Minden *case*-hez hozzáadhat kommentet vagy [#Attribútumok] a `addComment()` vagy `addAttribute()` segítségével.


Névtelen osztályok
------------------

Névként `null`-t adunk át, és máris van egy névtelen osztályunk:

```php
$class = new Nette\PhpGenerator\ClassType(null);
$class->addMethod('__construct')
	->addParameter('foo');

echo '$obj = new class ($val) ' . $class . ';';
```

Eredmény:

```php
$obj = new class ($val) {

	public function __construct($foo)
	{
	}
};
```


Globális függvények
-------------------

A függvények kódját a [GlobalFunction |api:Nette\PhpGenerator\GlobalFunction] osztály generálja:

```php
$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->setBody('return $a + $b;');
$function->addParameter('a');
$function->addParameter('b');
echo $function;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szerinti kimenethez
// echo (new Nette\PhpGenerator\PsrPrinter)->printFunction($function);
```

Eredmény:

```php
function foo($a, $b)
{
	return $a + $b;
}
```


Névtelen függvények
-------------------

A névtelen függvények kódját a [Closure |api:Nette\PhpGenerator\Closure] osztály generálja:

```php
$closure = new Nette\PhpGenerator\Closure;
$closure->setBody('return $a + $b;');
$closure->addParameter('a');
$closure->addParameter('b');
$closure->addUse('c')
	->setReference();
echo $closure;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szerinti kimenethez
// echo (new Nette\PhpGenerator\PsrPrinter)->printClosure($closure);
```

Eredmény:

```php
function ($a, $b) use (&$c) {
	return $a + $b;
}
```


Rövidített nyíl függvények
--------------------------

Kiírhat egy rövidített névtelen függvényt is a printer segítségével:

```php
$closure = new Nette\PhpGenerator\Closure;
$closure->setBody('$a + $b');
$closure->addParameter('a');
$closure->addParameter('b');

echo (new Nette\PhpGenerator\Printer)->printArrowFunction($closure);
```

Eredmény:

```php
fn($a, $b) => $a + $b
```


Metódus és függvény szignatúrák
-------------------------------

A metódusokat a [Method |api:Nette\PhpGenerator\Method] osztály reprezentálja. Beállíthatja a láthatóságot, a visszatérési értéket, hozzáadhat kommenteket, [attribútumokat |#Attribútumok] stb.:

```php
$method = $class->addMethod('count')
	->addComment('Számold meg.')
	->setFinal()
	->setProtected()
	->setReturnType('?int');
```

Az egyes paramétereket a [Parameter |api:Nette\PhpGenerator\Parameter] osztály reprezentálja. Ismét beállíthat minden elképzelhető tulajdonságot:

```php
$method->addParameter('items', []) // $items = []
	->setReference()           // &$items = []
	->setType('array');        // array &$items = []

// function count(array &$items = [])
```

Az ún. variadics paraméterek (vagy splat operátor) definiálására a `setVariadic()` szolgál:

```php
$method = $class->addMethod('count');
$method->setVariadic(true);
$method->addParameter('items');
```

Generálja:

```php
function count(...$items)
{
}
```


Metódus és függvény törzsek
---------------------------

A törzset átadhatjuk egyszerre a `setBody()` metódusnak, vagy fokozatosan (soronként) az `addBody()` ismételt hívásával:

```php
$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->addBody('$a = rand(10, 20);');
$function->addBody('return $a;');
echo $function;
```

Eredmény

```php
function foo()
{
	$a = rand(10, 20);
	return $a;
}
```

Speciális helyettesítő karaktereket használhat a változók egyszerű beillesztéséhez.

Egyszerű helyettesítő szimbólumok `?`

```php
$str = 'any string';
$num = 3;
$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->addBody('return substr(?, ?);', [$str, $num]);
echo $function;
```

Eredmény

```php
function foo()
{
	return substr('any string', 3);
}
```

Helyettesítő karakter variadic-hoz `...?`

```php
$items = [1, 2, 3];
$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->setBody('myfunc(...?);', [$items]);
echo $function;
```

Eredmény:

```php
function foo()
{
	myfunc(1, 2, 3);
}
```

Használhat névvel ellátott paramétereket is a PHP 8-hoz a `...?:` segítségével

```php
$items = ['foo' => 1, 'bar' => true];
$function->setBody('myfunc(...?:);', [$items]);

// myfunc(foo: 1, bar: true);
```

A helyettesítő szimbólumot a `\` karakterrel lehet escape-elni `\?`

```php
$num = 3;
$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->addParameter('a');
$function->addBody('return $a \? 10 : ?;', [$num]);
echo $function;
```

Eredmény:

```php
function foo($a)
{
	return $a ? 10 : 3;
}
```


Printer és PSR megfelelőség
---------------------------

A PHP kód generálására a [Printer |api:Nette\PhpGenerator\Printer] osztály szolgál:

```php
$class = new Nette\PhpGenerator\ClassType('Demo');
// ...

$printer = new Nette\PhpGenerator\Printer;
echo $printer->printClass($class); // ugyanaz, mint: echo $class
```

Képes generálni az összes többi elem kódját, kínál metódusokat, mint a `printFunction()`, `printNamespace()`, stb.

Rendelkezésre áll a `PsrPrinter` osztály is, amelynek kimenete megfelel a PSR-2 / PSR-12 / PER kódolási stílusnak:

```php
$printer = new Nette\PhpGenerator\PsrPrinter;
echo $printer->printClass($class);
```

Szeretné testre szabni a viselkedést? Hozzon létre saját verziót a `Printer` osztály öröklésével. Ezeket a változókat lehet újrakonfigurálni:

```php
class MyPrinter extends Nette\PhpGenerator\Printer
{
	// sor hossza, amely után sortörés történik
	public int $wrapLength = 120;
	// behúzás karaktere, helyettesíthető szóközök sorozatával
	public string $indentation = "\t";
	// üres sorok száma a propertyk között
	public int $linesBetweenProperties = 0;
	// üres sorok száma a metódusok között
	public int $linesBetweenMethods = 2;
	// üres sorok száma az 'use statements' csoportok között osztályokhoz, függvényekhez és konstansokhoz
	public int $linesBetweenUseTypes = 0;
	// nyitó kapcsos zárójel pozíciója függvényeknél és metódusoknál
	public bool $bracesOnNextLine = true;
	// helyezzen egy paramétert egy sorba, még akkor is, ha attribútuma van vagy promoted
	public bool $singleParameterOnOneLine = false;
	// kihagyja azokat a névtereket, amelyek nem tartalmaznak osztályt vagy függvényt
	public bool $omitEmptyNamespaces = true;
	// elválasztó a jobb zárójel és a függvények és metódusok visszatérési típusa között
	public string $returnTypeColon = ': ';
}
```

Hogyan és miért különbözik valójában a standard `Printer` és a `PsrPrinter`? Miért nincs csak egy printer a csomagban, mégpedig a `PsrPrinter`?

A standard `Printer` úgy formázza a kódot, ahogyan azt az egész Nette-ben tesszük. Mivel a Nette sokkal korábban jött létre, mint a PSR, és mivel a PSR évekig nem szállított időben szabványokat, hanem például többéves késéssel az új PHP funkció bevezetése után, előfordult, hogy a [kódolási szabvány |contributing:coding-standard] néhány apróságban eltér. A nagyobb különbség csak a tabulátorok használata szóközök helyett. Tudjuk, hogy a tabulátorok használata projektjeinkben lehetővé teszi a szélesség testreszabását, ami [látássérültek számára elengedhetetlen |contributing:coding-standard#Tabulátorok szóközök helyett]. Egy apró eltérés példája a kapcsos zárójel elhelyezése külön sorban a függvényeknél és metódusoknál, és ez mindig így van. A PSR ajánlása számunkra logikátlannak tűnik, és [a kód olvashatóságának csökkenéséhez |contributing:coding-standard#Tördelés és zárójelek] vezet.


Típusok
-------

Minden típust vagy union/intersection típust átadhatunk stringként, használhatunk előre definiált konstansokat is a natív típusokhoz:

```php
use Nette\PhpGenerator\Type;

$member->setType('array'); // vagy Type::Array;
$member->setType('?array'); // vagy Type::nullable(Type::Array);
$member->setType('array|string'); // vagy Type::union(Type::Array, Type::String)
$member->setType('Foo&Bar'); // vagy Type::intersection(Foo::class, Bar::class)
$member->setType(null); // eltávolítja a típust
```

Ugyanez vonatkozik a `setReturnType()` metódusra is.


Literálok
---------

A `Literal` segítségével tetszőleges PHP kódot adhatunk át, például propertyk vagy paraméterek alapértelmezett értékeihez stb.:

```php
use Nette\PhpGenerator\Literal;

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

$class->addProperty('foo', new Literal('Iterator::SELF_FIRST'));

$class->addMethod('bar')
	->addParameter('id', new Literal('1 + 2'));

echo $class;
```

Eredmény:

```php
class Demo
{
	public $foo = Iterator::SELF_FIRST;

	public function bar($id = 1 + 2)
	{
	}
}
```

Paramétereket is átadhat a `Literal`-nak, és hagyhatja, hogy érvényes PHP kóddá formázza őket [helyettesítő karaktereket |#Metódus és függvény törzsek] használva:

```php
new Literal('substr(?, ?)', [$a, $b]);
// generál például: substr('hello', 5);
```

Egy új objektum létrehozását reprezentáló literált könnyen generálhatunk a `new` metódussal:

```php
Literal::new(Demo::class, [$a, 'foo' => $b]);
// generál például: new Demo(10, foo: 20)
```


Attribútumok
------------

A PHP 8 attribútumokat hozzáadhatja az összes osztályhoz, metódushoz, propertyhez, konstanshoz, enumhoz, függvényhez, closure-höz és paraméterhez. Paraméterértékként [#Literálok] is használhatók.

```php
$class = new Nette\PhpGenerator\ClassType('Demo');
$class->addAttribute('Table', [
	'name' => 'user',
	'constraints' => [
		Literal::new('UniqueConstraint', ['name' => 'ean', 'columns' => ['ean']]),
	],
]);

$class->addProperty('list')
	->addAttribute('Deprecated');

$method = $class->addMethod('count')
	->addAttribute('Foo\Cached', ['mode' => true]);

$method->addParameter('items')
	->addAttribute('Bar');

echo $class;
```

Eredmény:

```php
#[Table(name: 'user', constraints: [new UniqueConstraint(name: 'ean', columns: ['ean'])])]
class Demo
{
	#[Deprecated]
	public $list;


	#[Foo\Cached(mode: true)]
	public function count(
		#[Bar]
		$items,
	) {
	}
}
```


Property Hookok
---------------

A property hookok segítségével ([PropertyHook|api:Nette\PhpGenerator\PropertyHook] osztály által reprezentálva) definiálhat get és set műveleteket a propertykhez, ami a PHP 8.4-ben bevezetett funkció:

```php
$class = new Nette\PhpGenerator\ClassType('Demo');
$prop = $class->addProperty('firstName')
    ->setType('string');

$prop->addHook('set', 'strtolower($value)')
    ->addParameter('value')
	    ->setType('string');

$prop->addHook('get')
	->setBody('return ucfirst($this->firstName);');

echo $class;
```

Generálja:

```php
class Demo
{
    public string $firstName {
        set(string $value) => strtolower($value);
        get {
            return ucfirst($this->firstName);
        }
    }
}
```

A propertyk és property hookok lehetnek absztraktak vagy finálak:

```php
$class->addProperty('id')
    ->setType('int')
    ->addHook('get')
        ->setAbstract();

$class->addProperty('role')
    ->setType('string')
    ->addHook('set', 'strtolower($value)')
        ->setFinal();
```


Aszimmetrikus láthatóság
------------------------

A PHP 8.4 bevezeti az aszimmetrikus láthatóságot a propertykhez. Különböző hozzáférési szinteket állíthat be az olvasáshoz és íráshoz.

A láthatóságot beállíthatja vagy a `setVisibility()` metódussal két paraméterrel, vagy a `setPublic()`, `setProtected()` vagy `setPrivate()` metódusokkal a `mode` paraméterrel, amely meghatározza, hogy a láthatóság az olvasásra vagy az írásra vonatkozik-e. Az alapértelmezett mód `'get'`.

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

$class->addProperty('name')
    ->setType('string')
    ->setVisibility('public', 'private'); // public olvasáshoz, private íráshoz

$class->addProperty('id')
    ->setType('int')
    ->setProtected('set'); // protected íráshoz

echo $class;
```

Generálja:

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

    protected(set) int $id;
}
```


Névtér
------

Az osztályokat, propertyket, interfészeket és enumokat (továbbiakban osztályok) csoportosíthatjuk névterekbe, amelyeket a [PhpNamespace |api:Nette\PhpGenerator\PhpNamespace] osztály reprezentál:

```php
$namespace = new Nette\PhpGenerator\PhpNamespace('Foo');

// új osztályok létrehozása a névtérben
$class = $namespace->addClass('Task');
$interface = $namespace->addInterface('Countable');
$trait = $namespace->addTrait('NameAware');

// vagy meglévő osztály beillesztése a névtérbe
$class = new Nette\PhpGenerator\ClassType('Task');
$namespace->add($class);
```

Ha az osztály már létezik, kivétel dobódik.

Definiálhat use klózokat:

```php
// use Http\Request;
$namespace->addUse(Http\Request::class);
// use Http\Request as HttpReq;
$namespace->addUse(Http\Request::class, 'HttpReq');
// use function iter\range;
$namespace->addUseFunction('iter\range');
```

Ha egyszerűsíteni szeretné a teljesen minősített osztály-, függvény- vagy konstansnevet a definiált aliasok szerint, használja a `simplifyName` metódust:

```php
echo $namespace->simplifyName('Foo\Bar'); // 'Bar', mert a 'Foo' az aktuális névtér
echo $namespace->simplifyName('iter\range', $namespace::NameFunction); // 'range', a definiált use-statement miatt
```

Az egyszerűsített osztály-, függvény- vagy konstansnevet fordítva átalakíthatja teljesen minősített névre a `resolveName` metódussal:

```php
echo $namespace->resolveName('Bar'); // 'Foo\Bar'
echo $namespace->resolveName('range', $namespace::NameFunction); // 'iter\range'
```


Osztálynevek fordítása
----------------------

**Ha egy osztály egy névtér része, kissé eltérően jelenik meg:** minden típus (például typehintek, visszatérési típusok, szülőosztály neve, implementált interfészek, használt propertyk és attribútumok) automatikusan *lefordításra* kerül (hacsak nem kapcsolja ki, lásd alább). Ez azt jelenti, hogy a definíciókban **teljes osztályneveket kell használnia**, és ezeket aliasokra (a use klózok szerint) vagy teljesen minősített nevekre cseréli a végső kódban:

```php
$namespace = new Nette\PhpGenerator\PhpNamespace('Foo');
$namespace->addUse('Bar\AliasedClass');

$class = $namespace->addClass('Demo');
$class->addImplement('Foo\A') // A-ra lesz egyszerűsítve
	->addTrait('Bar\AliasedClass'); // AliasedClass-ra lesz egyszerűsítve

$method = $class->addMethod('method');
$method->addComment('@return ' . $namespace->simplifyType('Foo\D')); // kommentekben manuálisan egyszerűsítünk
$method->addParameter('arg')
	->setType('Bar\OtherClass'); // \Bar\OtherClass-ra lesz fordítva

echo $namespace;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szerinti kimenethez
// echo (new Nette\PhpGenerator\PsrPrinter)->printNamespace($namespace);
```

Eredmény:

```php
namespace Foo;

use Bar\AliasedClass;

class Demo implements A
{
	use AliasedClass;

	/**
	 * @return D
	 */
	public function method(\Bar\OtherClass $arg)
	{
	}
}
```

Az automatikus fordítást így lehet kikapcsolni:

```php
$printer = new Nette\PhpGenerator\Printer; // vagy PsrPrinter
$printer->setTypeResolving(false);
echo $printer->printNamespace($namespace);
```


PHP fájlok
----------

Az osztályokat, függvényeket és névtereket PHP fájlokba csoportosíthatjuk, amelyeket a [PhpFile|api:Nette\PhpGenerator\PhpFile] osztály reprezentál:

```php
$file = new Nette\PhpGenerator\PhpFile;
$file->addComment('Ez a fájl automatikusan generált.');
$file->setStrictTypes(); // hozzáadja declare(strict_types=1)

$class = $file->addClass('Foo\A');
$function = $file->addFunction('Foo\foo');

// vagy
// $namespace = $file->addNamespace('Foo');
// $class = $namespace->addClass('A');
// $function = $namespace->addFunction('foo');

echo $file;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szerinti kimenethez
// echo (new Nette\PhpGenerator\PsrPrinter)->printFile($file);
```

Eredmény:

```php
<?php

/**
 * Ez a fájl automatikusan generált.
 */

declare(strict_types=1);

namespace Foo;

class A
{
}

function foo()
{
}
```

**Figyelmeztetés:** A fájlokhoz nem lehet további kódot hozzáadni a függvényeken és osztályokon kívül.


Generálás meglévők alapján
--------------------------

Amellett, hogy az osztályokat és függvényeket a fent leírt API segítségével modellezheti, automatikusan is generáltathatja őket meglévő minták alapján:

```php
// létrehoz egy osztályt, amely megegyezik a PDO osztállyal
$class = Nette\PhpGenerator\ClassType::from(PDO::class);

// létrehoz egy függvényt, amely azonos a trim() függvénnyel
$function = Nette\PhpGenerator\GlobalFunction::from('trim');

// létrehoz egy closure-t a megadott alapján
$closure = Nette\PhpGenerator\Closure::from(
	function (stdClass $a, $b = null) {},
);
```

A függvények és metódusok törzsei alapértelmezés szerint üresek. Ha ezeket is be szeretné tölteni, használja ezt a módszert (szükséges a `nikic/php-parser` csomag telepítése):

```php
$class = Nette\PhpGenerator\ClassType::from(Foo::class, withBodies: true);

$function = Nette\PhpGenerator\GlobalFunction::from('foo', withBody: true);
```


Betöltés PHP fájlokból
----------------------

Függvényeket, osztályokat, interfészeket és enumokat közvetlenül PHP kódot tartalmazó stringből is betölthet. Például így hozunk létre egy `ClassType` objektumot:

```php
$class = Nette\PhpGenerator\ClassType::fromCode(<<<XX
	<?php

	class Demo
	{
		public $foo;
	}
	XX);
```

Ha osztályokat PHP kódból tölt be, az egysoros kommentek a metódustörzseken kívül (pl. propertyknél stb.) figyelmen kívül maradnak, mivel ez a könyvtár nem rendelkezik API-val a kezelésükhöz.

Közvetlenül betölthet egy teljes PHP fájlt is, amely tetszőleges számú osztályt, függvényt vagy akár névteret tartalmazhat:

```php
$file = Nette\PhpGenerator\PhpFile::fromCode(file_get_contents('classes.php'));
```

Betöltődik a fájl bevezető kommentje és a `strict_types` deklaráció is. Ezzel szemben minden más globális kód figyelmen kívül marad.

Szükséges, hogy a `nikic/php-parser` telepítve legyen.

.[note]
Ha globális kódot kell manipulálnia fájlokban vagy egyes utasításokat metódustörzsekben, jobb közvetlenül a `nikic/php-parser` könyvtárat használni.


Class Manipulator
-----------------

A [ClassManipulator|api:Nette\PhpGenerator\ClassManipulator] osztály eszközöket biztosít az osztályok manipulálásához.

```php
$class = new Nette\PhpGenerator\ClassType('Demo');
$manipulator = new Nette\PhpGenerator\ClassManipulator($class);
```

Az `inheritMethod()` metódus átmásol egy metódust a szülőosztályból vagy implementált interfészből az Ön osztályába. Ez lehetővé teszi a metódus felülírását vagy a szignatúrájának kiterjesztését:

```php
$method = $manipulator->inheritMethod('bar');
$method->setBody('...');
```

Az `inheritProperty()` metódus átmásol egy propertyt a szülőosztályból az Ön osztályába. Ez akkor hasznos, ha ugyanazt a propertyt szeretné az osztályában, de esetleg más alapértelmezett értékkel:

```php
$property = $manipulator->inheritProperty('foo');
$property->setValue('new value');
```

Az `implement()` metódus automatikusan implementálja az összes metódust és propertyt a megadott interfészből vagy absztrakt osztályból az Ön osztályában:

```php
$manipulator->implement(SomeInterface::class);
// Most az Ön osztálya implementálja a SomeInterface-t és tartalmazza annak összes metódusát
```


Változók kiírása
----------------

A `Dumper` osztály átalakít egy változót elemezhető PHP kóddá. Jobb és áttekinthetőbb kimenetet biztosít, mint a standard `var_export()` függvény.

```php
$dumper = new Nette\PhpGenerator\Dumper;

$var = ['a', 'b', 123];

echo $dumper->dump($var); // kiírja ['a', 'b', 123]
```


Kompatibilitási táblázat
------------------------

A PhpGenerator 4.1 kompatibilis a PHP 8.0-tól 8.4-ig.

{{leftbar: nette:@menu-topics}}

Nette PhpGenerator

Eszközt keres osztályok, függvények vagy teljes PHP fájlok kódjának generálásához?
  • Ismeri az összes legújabb PHP funkciót (mint a property hookok, enumok, attribútumok stb.)
  • Lehetővé teszi a meglévő osztályok egyszerű módosítását
  • A kimeneti kód megfelel a PSR-12 / PER kódolási stílusnak
  • Érett, stabil és széles körben használt könyvtár

Telepítés

A könyvtárat a Composer segítségével töltheti le és telepítheti:

composer require nette/php-generator

A PHP kompatibilitást a kompatibilitási táblázatban találja.

Osztályok

Kezdjük rögtön egy példával egy osztály létrehozására a ClassType segítségével:

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

$class
	->setFinal()
	->setExtends(ParentClass::class)
	->addImplement(Countable::class)
	->addComment("Osztály leírása.\nMásodik sor\n")
	->addComment('@property-read Nette\Forms\Form $form');

// a kódot egyszerűen generálhatja stringgé alakítással vagy az echo használatával:
echo $class;

A következő eredményt adja vissza:

/**
 * Osztály leírása
 * Második sor
 *
 * @property-read Nette\Forms\Form $form
 */
final class Demo extends ParentClass implements Countable
{
}

A kód generálásához használhatunk egy ún. printert is, amelyet az echo $class-szal ellentétben tovább konfigurálni tudunk:

$printer = new Nette\PhpGenerator\Printer;
echo $printer->printClass($class);

Hozzáadhatunk konstansokat (Constant osztály) és propertyket (Property osztály):

$class->addConstant('ID', 123)
	->setProtected() // konstansok láthatósága
	->setType('int')
	->setFinal();

$class->addProperty('items', [1, 2, 3])
	->setPrivate() // vagy setVisibility('private')
	->setStatic()
	->addComment('@var int[]');

$class->addProperty('list')
	->setType('?array')
	->setInitialized(); // kiírja '= null'

Generálja:

final protected const int ID = 123;

/** @var int[] */
private static $items = [1, 2, 3];

public ?array $list = null;

És hozzáadhatunk metódusokat:

$method = $class->addMethod('count')
	->addComment('Számold meg.')
	->setFinal()
	->setProtected()
	->setReturnType('?int') // visszatérési típusok metódusoknál
	->setBody('return count($items ?: $this->items);');

$method->addParameter('items', []) // $items = []
	->setReference()           // &$items = []
	->setType('array');        // array &$items = []

Az eredmény:

/**
 * Számold meg.
 */
final protected function count(array &$items = []): ?int
{
	return count($items ?: $this->items);
}

A PHP 8.0 által bevezetett promoted paramétereket átadhatjuk a konstruktornak:

$method = $class->addMethod('__construct');
$method->addPromotedParameter('name');
$method->addPromotedParameter('args', [])
	->setPrivate();

Az eredmény:

public function __construct(
	public $name,
	private $args = [],
) {
}

A csak olvasható propertyket és osztályokat a setReadOnly() függvénnyel lehet megjelölni.


Ha a hozzáadott property, konstans, metódus vagy paraméter már létezik, kivétel dobódik.

Az osztály tagjait eltávolíthatjuk a removeProperty(), removeConstant(), removeMethod() vagy removeParameter() segítségével.

Az osztályhoz hozzáadhatunk meglévő Method, Property vagy Constant objektumokat is:

$method = new Nette\PhpGenerator\Method('getHandle');
$property = new Nette\PhpGenerator\Property('handle');
$const = new Nette\PhpGenerator\Constant('ROLE');

$class = (new Nette\PhpGenerator\ClassType('Demo'))
	->addMember($method)
	->addMember($property)
	->addMember($const);

Klónozhatunk meglévő metódusokat, propertyket és konstansokat más néven a cloneWithName() segítségével:

$methodCount = $class->getMethod('count');
$methodRecount = $methodCount->cloneWithName('recount');
$class->addMember($methodRecount);

Interfész vagy Trait

Létrehozhat interfészeket és traitteket (InterfaceType és TraitType osztályok):

$interface = new Nette\PhpGenerator\InterfaceType('MyInterface');
$trait = new Nette\PhpGenerator\TraitType('MyTrait');

Trait használata:

$class = new Nette\PhpGenerator\ClassType('Demo');
$class->addTrait('SmartObject');
$class->addTrait('MyTrait')
	->addResolution('sayHello as protected')
	->addComment('@use MyTrait<Foo>');
echo $class;

Eredmény:

class Demo
{
	use SmartObject;
	/** @use MyTrait<Foo> */
	use MyTrait {
		sayHello as protected;
	}
}

Enumok

A PHP 8.1 által bevezetett enumokat könnyen létrehozhatja így: (EnumType osztály):

$enum = new Nette\PhpGenerator\EnumType('Suit');
$enum->addCase('Clubs');
$enum->addCase('Diamonds');
$enum->addCase('Hearts');
$enum->addCase('Spades');

echo $enum;

Eredmény:

enum Suit
{
	case Clubs;
	case Diamonds;
	case Hearts;
	case Spades;
}

Definiálhat skaláris ekvivalenseket is, és létrehozhat egy „backed“ enumot:

$enum->addCase('Clubs', '♣');
$enum->addCase('Diamonds', '♦');

Minden case-hez hozzáadhat kommentet vagy Attribútumok a addComment() vagy addAttribute() segítségével.

Névtelen osztályok

Névként null-t adunk át, és máris van egy névtelen osztályunk:

$class = new Nette\PhpGenerator\ClassType(null);
$class->addMethod('__construct')
	->addParameter('foo');

echo '$obj = new class ($val) ' . $class . ';';

Eredmény:

$obj = new class ($val) {

	public function __construct($foo)
	{
	}
};

Globális függvények

A függvények kódját a GlobalFunction osztály generálja:

$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->setBody('return $a + $b;');
$function->addParameter('a');
$function->addParameter('b');
echo $function;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szerinti kimenethez
// echo (new Nette\PhpGenerator\PsrPrinter)->printFunction($function);

Eredmény:

function foo($a, $b)
{
	return $a + $b;
}

Névtelen függvények

A névtelen függvények kódját a Closure osztály generálja:

$closure = new Nette\PhpGenerator\Closure;
$closure->setBody('return $a + $b;');
$closure->addParameter('a');
$closure->addParameter('b');
$closure->addUse('c')
	->setReference();
echo $closure;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szerinti kimenethez
// echo (new Nette\PhpGenerator\PsrPrinter)->printClosure($closure);

Eredmény:

function ($a, $b) use (&$c) {
	return $a + $b;
}

Rövidített nyíl függvények

Kiírhat egy rövidített névtelen függvényt is a printer segítségével:

$closure = new Nette\PhpGenerator\Closure;
$closure->setBody('$a + $b');
$closure->addParameter('a');
$closure->addParameter('b');

echo (new Nette\PhpGenerator\Printer)->printArrowFunction($closure);

Eredmény:

fn($a, $b) => $a + $b

Metódus és függvény szignatúrák

A metódusokat a Method osztály reprezentálja. Beállíthatja a láthatóságot, a visszatérési értéket, hozzáadhat kommenteket, attribútumokat stb.:

$method = $class->addMethod('count')
	->addComment('Számold meg.')
	->setFinal()
	->setProtected()
	->setReturnType('?int');

Az egyes paramétereket a Parameter osztály reprezentálja. Ismét beállíthat minden elképzelhető tulajdonságot:

$method->addParameter('items', []) // $items = []
	->setReference()           // &$items = []
	->setType('array');        // array &$items = []

// function count(array &$items = [])

Az ún. variadics paraméterek (vagy splat operátor) definiálására a setVariadic() szolgál:

$method = $class->addMethod('count');
$method->setVariadic(true);
$method->addParameter('items');

Generálja:

function count(...$items)
{
}

Metódus és függvény törzsek

A törzset átadhatjuk egyszerre a setBody() metódusnak, vagy fokozatosan (soronként) az addBody() ismételt hívásával:

$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->addBody('$a = rand(10, 20);');
$function->addBody('return $a;');
echo $function;

Eredmény

function foo()
{
	$a = rand(10, 20);
	return $a;
}

Speciális helyettesítő karaktereket használhat a változók egyszerű beillesztéséhez.

Egyszerű helyettesítő szimbólumok ?

$str = 'any string';
$num = 3;
$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->addBody('return substr(?, ?);', [$str, $num]);
echo $function;

Eredmény

function foo()
{
	return substr('any string', 3);
}

Helyettesítő karakter variadic-hoz ...?

$items = [1, 2, 3];
$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->setBody('myfunc(...?);', [$items]);
echo $function;

Eredmény:

function foo()
{
	myfunc(1, 2, 3);
}

Használhat névvel ellátott paramétereket is a PHP 8-hoz a ...?: segítségével

$items = ['foo' => 1, 'bar' => true];
$function->setBody('myfunc(...?:);', [$items]);

// myfunc(foo: 1, bar: true);

A helyettesítő szimbólumot a \ karakterrel lehet escape-elni \?

$num = 3;
$function = new Nette\PhpGenerator\GlobalFunction('foo');
$function->addParameter('a');
$function->addBody('return $a \? 10 : ?;', [$num]);
echo $function;

Eredmény:

function foo($a)
{
	return $a ? 10 : 3;
}

Printer és PSR megfelelőség

A PHP kód generálására a Printer osztály szolgál:

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

$printer = new Nette\PhpGenerator\Printer;
echo $printer->printClass($class); // ugyanaz, mint: echo $class

Képes generálni az összes többi elem kódját, kínál metódusokat, mint a printFunction(), printNamespace(), stb.

Rendelkezésre áll a PsrPrinter osztály is, amelynek kimenete megfelel a PSR-2 / PSR-12 / PER kódolási stílusnak:

$printer = new Nette\PhpGenerator\PsrPrinter;
echo $printer->printClass($class);

Szeretné testre szabni a viselkedést? Hozzon létre saját verziót a Printer osztály öröklésével. Ezeket a változókat lehet újrakonfigurálni:

class MyPrinter extends Nette\PhpGenerator\Printer
{
	// sor hossza, amely után sortörés történik
	public int $wrapLength = 120;
	// behúzás karaktere, helyettesíthető szóközök sorozatával
	public string $indentation = "\t";
	// üres sorok száma a propertyk között
	public int $linesBetweenProperties = 0;
	// üres sorok száma a metódusok között
	public int $linesBetweenMethods = 2;
	// üres sorok száma az 'use statements' csoportok között osztályokhoz, függvényekhez és konstansokhoz
	public int $linesBetweenUseTypes = 0;
	// nyitó kapcsos zárójel pozíciója függvényeknél és metódusoknál
	public bool $bracesOnNextLine = true;
	// helyezzen egy paramétert egy sorba, még akkor is, ha attribútuma van vagy promoted
	public bool $singleParameterOnOneLine = false;
	// kihagyja azokat a névtereket, amelyek nem tartalmaznak osztályt vagy függvényt
	public bool $omitEmptyNamespaces = true;
	// elválasztó a jobb zárójel és a függvények és metódusok visszatérési típusa között
	public string $returnTypeColon = ': ';
}

Hogyan és miért különbözik valójában a standard Printer és a PsrPrinter? Miért nincs csak egy printer a csomagban, mégpedig a PsrPrinter?

A standard Printer úgy formázza a kódot, ahogyan azt az egész Nette-ben tesszük. Mivel a Nette sokkal korábban jött létre, mint a PSR, és mivel a PSR évekig nem szállított időben szabványokat, hanem például többéves késéssel az új PHP funkció bevezetése után, előfordult, hogy a kódolási szabvány néhány apróságban eltér. A nagyobb különbség csak a tabulátorok használata szóközök helyett. Tudjuk, hogy a tabulátorok használata projektjeinkben lehetővé teszi a szélesség testreszabását, ami látássérültek számára elengedhetetlen. Egy apró eltérés példája a kapcsos zárójel elhelyezése külön sorban a függvényeknél és metódusoknál, és ez mindig így van. A PSR ajánlása számunkra logikátlannak tűnik, és a kód olvashatóságának csökkenéséhez vezet.

Típusok

Minden típust vagy union/intersection típust átadhatunk stringként, használhatunk előre definiált konstansokat is a natív típusokhoz:

use Nette\PhpGenerator\Type;

$member->setType('array'); // vagy Type::Array;
$member->setType('?array'); // vagy Type::nullable(Type::Array);
$member->setType('array|string'); // vagy Type::union(Type::Array, Type::String)
$member->setType('Foo&Bar'); // vagy Type::intersection(Foo::class, Bar::class)
$member->setType(null); // eltávolítja a típust

Ugyanez vonatkozik a setReturnType() metódusra is.

Literálok

A Literal segítségével tetszőleges PHP kódot adhatunk át, például propertyk vagy paraméterek alapértelmezett értékeihez stb.:

use Nette\PhpGenerator\Literal;

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

$class->addProperty('foo', new Literal('Iterator::SELF_FIRST'));

$class->addMethod('bar')
	->addParameter('id', new Literal('1 + 2'));

echo $class;

Eredmény:

class Demo
{
	public $foo = Iterator::SELF_FIRST;

	public function bar($id = 1 + 2)
	{
	}
}

Paramétereket is átadhat a Literal-nak, és hagyhatja, hogy érvényes PHP kóddá formázza őket helyettesítő karaktereket használva:

new Literal('substr(?, ?)', [$a, $b]);
// generál például: substr('hello', 5);

Egy új objektum létrehozását reprezentáló literált könnyen generálhatunk a new metódussal:

Literal::new(Demo::class, [$a, 'foo' => $b]);
// generál például: new Demo(10, foo: 20)

Attribútumok

A PHP 8 attribútumokat hozzáadhatja az összes osztályhoz, metódushoz, propertyhez, konstanshoz, enumhoz, függvényhez, closure-höz és paraméterhez. Paraméterértékként Literálok is használhatók.

$class = new Nette\PhpGenerator\ClassType('Demo');
$class->addAttribute('Table', [
	'name' => 'user',
	'constraints' => [
		Literal::new('UniqueConstraint', ['name' => 'ean', 'columns' => ['ean']]),
	],
]);

$class->addProperty('list')
	->addAttribute('Deprecated');

$method = $class->addMethod('count')
	->addAttribute('Foo\Cached', ['mode' => true]);

$method->addParameter('items')
	->addAttribute('Bar');

echo $class;

Eredmény:

#[Table(name: 'user', constraints: [new UniqueConstraint(name: 'ean', columns: ['ean'])])]
class Demo
{
	#[Deprecated]
	public $list;


	#[Foo\Cached(mode: true)]
	public function count(
		#[Bar]
		$items,
	) {
	}
}

Property Hookok

A property hookok segítségével (PropertyHook osztály által reprezentálva) definiálhat get és set műveleteket a propertykhez, ami a PHP 8.4-ben bevezetett funkció:

$class = new Nette\PhpGenerator\ClassType('Demo');
$prop = $class->addProperty('firstName')
    ->setType('string');

$prop->addHook('set', 'strtolower($value)')
    ->addParameter('value')
	    ->setType('string');

$prop->addHook('get')
	->setBody('return ucfirst($this->firstName);');

echo $class;

Generálja:

class Demo
{
    public string $firstName {
        set(string $value) => strtolower($value);
        get {
            return ucfirst($this->firstName);
        }
    }
}

A propertyk és property hookok lehetnek absztraktak vagy finálak:

$class->addProperty('id')
    ->setType('int')
    ->addHook('get')
        ->setAbstract();

$class->addProperty('role')
    ->setType('string')
    ->addHook('set', 'strtolower($value)')
        ->setFinal();

Aszimmetrikus láthatóság

A PHP 8.4 bevezeti az aszimmetrikus láthatóságot a propertykhez. Különböző hozzáférési szinteket állíthat be az olvasáshoz és íráshoz.

A láthatóságot beállíthatja vagy a setVisibility() metódussal két paraméterrel, vagy a setPublic(), setProtected() vagy setPrivate() metódusokkal a mode paraméterrel, amely meghatározza, hogy a láthatóság az olvasásra vagy az írásra vonatkozik-e. Az alapértelmezett mód 'get'.

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

$class->addProperty('name')
    ->setType('string')
    ->setVisibility('public', 'private'); // public olvasáshoz, private íráshoz

$class->addProperty('id')
    ->setType('int')
    ->setProtected('set'); // protected íráshoz

echo $class;

Generálja:

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

    protected(set) int $id;
}

Névtér

Az osztályokat, propertyket, interfészeket és enumokat (továbbiakban osztályok) csoportosíthatjuk névterekbe, amelyeket a PhpNamespace osztály reprezentál:

$namespace = new Nette\PhpGenerator\PhpNamespace('Foo');

// új osztályok létrehozása a névtérben
$class = $namespace->addClass('Task');
$interface = $namespace->addInterface('Countable');
$trait = $namespace->addTrait('NameAware');

// vagy meglévő osztály beillesztése a névtérbe
$class = new Nette\PhpGenerator\ClassType('Task');
$namespace->add($class);

Ha az osztály már létezik, kivétel dobódik.

Definiálhat use klózokat:

// use Http\Request;
$namespace->addUse(Http\Request::class);
// use Http\Request as HttpReq;
$namespace->addUse(Http\Request::class, 'HttpReq');
// use function iter\range;
$namespace->addUseFunction('iter\range');

Ha egyszerűsíteni szeretné a teljesen minősített osztály-, függvény- vagy konstansnevet a definiált aliasok szerint, használja a simplifyName metódust:

echo $namespace->simplifyName('Foo\Bar'); // 'Bar', mert a 'Foo' az aktuális névtér
echo $namespace->simplifyName('iter\range', $namespace::NameFunction); // 'range', a definiált use-statement miatt

Az egyszerűsített osztály-, függvény- vagy konstansnevet fordítva átalakíthatja teljesen minősített névre a resolveName metódussal:

echo $namespace->resolveName('Bar'); // 'Foo\Bar'
echo $namespace->resolveName('range', $namespace::NameFunction); // 'iter\range'

Osztálynevek fordítása

Ha egy osztály egy névtér része, kissé eltérően jelenik meg: minden típus (például typehintek, visszatérési típusok, szülőosztály neve, implementált interfészek, használt propertyk és attribútumok) automatikusan lefordításra kerül (hacsak nem kapcsolja ki, lásd alább). Ez azt jelenti, hogy a definíciókban teljes osztályneveket kell használnia, és ezeket aliasokra (a use klózok szerint) vagy teljesen minősített nevekre cseréli a végső kódban:

$namespace = new Nette\PhpGenerator\PhpNamespace('Foo');
$namespace->addUse('Bar\AliasedClass');

$class = $namespace->addClass('Demo');
$class->addImplement('Foo\A') // A-ra lesz egyszerűsítve
	->addTrait('Bar\AliasedClass'); // AliasedClass-ra lesz egyszerűsítve

$method = $class->addMethod('method');
$method->addComment('@return ' . $namespace->simplifyType('Foo\D')); // kommentekben manuálisan egyszerűsítünk
$method->addParameter('arg')
	->setType('Bar\OtherClass'); // \Bar\OtherClass-ra lesz fordítva

echo $namespace;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szerinti kimenethez
// echo (new Nette\PhpGenerator\PsrPrinter)->printNamespace($namespace);

Eredmény:

namespace Foo;

use Bar\AliasedClass;

class Demo implements A
{
	use AliasedClass;

	/**
	 * @return D
	 */
	public function method(\Bar\OtherClass $arg)
	{
	}
}

Az automatikus fordítást így lehet kikapcsolni:

$printer = new Nette\PhpGenerator\Printer; // vagy PsrPrinter
$printer->setTypeResolving(false);
echo $printer->printNamespace($namespace);

PHP fájlok

Az osztályokat, függvényeket és névtereket PHP fájlokba csoportosíthatjuk, amelyeket a PhpFile osztály reprezentál:

$file = new Nette\PhpGenerator\PhpFile;
$file->addComment('Ez a fájl automatikusan generált.');
$file->setStrictTypes(); // hozzáadja declare(strict_types=1)

$class = $file->addClass('Foo\A');
$function = $file->addFunction('Foo\foo');

// vagy
// $namespace = $file->addNamespace('Foo');
// $class = $namespace->addClass('A');
// $function = $namespace->addFunction('foo');

echo $file;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szerinti kimenethez
// echo (new Nette\PhpGenerator\PsrPrinter)->printFile($file);

Eredmény:

<?php

/**
 * Ez a fájl automatikusan generált.
 */

declare(strict_types=1);

namespace Foo;

class A
{
}

function foo()
{
}

Figyelmeztetés: A fájlokhoz nem lehet további kódot hozzáadni a függvényeken és osztályokon kívül.

Generálás meglévők alapján

Amellett, hogy az osztályokat és függvényeket a fent leírt API segítségével modellezheti, automatikusan is generáltathatja őket meglévő minták alapján:

// létrehoz egy osztályt, amely megegyezik a PDO osztállyal
$class = Nette\PhpGenerator\ClassType::from(PDO::class);

// létrehoz egy függvényt, amely azonos a trim() függvénnyel
$function = Nette\PhpGenerator\GlobalFunction::from('trim');

// létrehoz egy closure-t a megadott alapján
$closure = Nette\PhpGenerator\Closure::from(
	function (stdClass $a, $b = null) {},
);

A függvények és metódusok törzsei alapértelmezés szerint üresek. Ha ezeket is be szeretné tölteni, használja ezt a módszert (szükséges a nikic/php-parser csomag telepítése):

$class = Nette\PhpGenerator\ClassType::from(Foo::class, withBodies: true);

$function = Nette\PhpGenerator\GlobalFunction::from('foo', withBody: true);

Betöltés PHP fájlokból

Függvényeket, osztályokat, interfészeket és enumokat közvetlenül PHP kódot tartalmazó stringből is betölthet. Például így hozunk létre egy ClassType objektumot:

$class = Nette\PhpGenerator\ClassType::fromCode(<<<XX
	<?php

	class Demo
	{
		public $foo;
	}
	XX);

Ha osztályokat PHP kódból tölt be, az egysoros kommentek a metódustörzseken kívül (pl. propertyknél stb.) figyelmen kívül maradnak, mivel ez a könyvtár nem rendelkezik API-val a kezelésükhöz.

Közvetlenül betölthet egy teljes PHP fájlt is, amely tetszőleges számú osztályt, függvényt vagy akár névteret tartalmazhat:

$file = Nette\PhpGenerator\PhpFile::fromCode(file_get_contents('classes.php'));

Betöltődik a fájl bevezető kommentje és a strict_types deklaráció is. Ezzel szemben minden más globális kód figyelmen kívül marad.

Szükséges, hogy a nikic/php-parser telepítve legyen.

Ha globális kódot kell manipulálnia fájlokban vagy egyes utasításokat metódustörzsekben, jobb közvetlenül a nikic/php-parser könyvtárat használni.

Class Manipulator

ClassManipulator osztály eszközöket biztosít az osztályok manipulálásához.

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

Az inheritMethod() metódus átmásol egy metódust a szülőosztályból vagy implementált interfészből az Ön osztályába. Ez lehetővé teszi a metódus felülírását vagy a szignatúrájának kiterjesztését:

$method = $manipulator->inheritMethod('bar');
$method->setBody('...');

Az inheritProperty() metódus átmásol egy propertyt a szülőosztályból az Ön osztályába. Ez akkor hasznos, ha ugyanazt a propertyt szeretné az osztályában, de esetleg más alapértelmezett értékkel:

$property = $manipulator->inheritProperty('foo');
$property->setValue('new value');

Az implement() metódus automatikusan implementálja az összes metódust és propertyt a megadott interfészből vagy absztrakt osztályból az Ön osztályában:

$manipulator->implement(SomeInterface::class);
// Most az Ön osztálya implementálja a SomeInterface-t és tartalmazza annak összes metódusát

Változók kiírása

A Dumper osztály átalakít egy változót elemezhető PHP kóddá. Jobb és áttekinthetőbb kimenetet biztosít, mint a standard var_export() függvény.

$dumper = new Nette\PhpGenerator\Dumper;

$var = ['a', 'b', 123];

echo $dumper->dump($var); // kiírja ['a', 'b', 123]

Kompatibilitási táblázat

A PhpGenerator 4.1 kompatibilis a PHP 8.0-tól 8.4-ig.