Nette Documentation Preview

syntax
PHP kód generátor
*****************

<div class=perex>
Olyan eszközt keres, amellyel PHP kódot generálhat osztályokhoz, függvényekhez vagy teljes fájlokhoz?

- Támogatja az összes legújabb PHP funkciót (mint például a property hooks, enums, attribútumok, stb.)
- Lehetővé teszi a meglévő osztályok egyszerű módosítását
- PSR-12 / PER kódolási stílusnak megfelelő kimenet
- Kiforrott, stabil és széles körben használt könyvtár
</div>


Telepítés .[#toc-installation]
------------------------------

Töltse le és telepítse a csomagot a [Composer |best-practices:composer] segítségével:

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

A PHP-kompatibilitásról lásd a [táblázatot |#Compatibility Table].


Osztályok .[#toc-classes]
-------------------------

Kezdjük egy egyszerű példával az osztály generálására a [ClassType |api:Nette\PhpGenerator\ClassType] használatával:

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

$class
	->setFinal()
	->setExtends(ParentClass::class)
	->addImplement(Countable::class)
	->addComment("Description of class.\nSecond line\n")
	->addComment('@property-read Nette\Forms\Form $form');

// PHP kód generálásához egyszerűen csak öntsd stringre, vagy használd az echo-t:
echo $class;
```

A következő eredményt adja ki:

```php
/**
 * Description of class.
 * Second line
 *
 * @property-read Nette\Forms\Form $form
 */
final class Demo extends ParentClass implements Countable
{
}
```

A kód generálásához használhatunk nyomtatót is, amelyet a `echo $class` címmel ellentétben [tovább konfigurálhatunk |#Printers and PSR compliance]:

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

Konstanciákat (class [Constant |api:Nette\PhpGenerator\Constant]) és tulajdonságokat (class [Property |api:Nette\PhpGenerator\Property]) adhatunk hozzá:

```php
$class->addConstant('ID', 123)
	->setProtected() // konstans láthatóság
	->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'
```

Ez 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 |#Method and Function Signature]:

```php
$method = $class->addMethod('count')
	->addComment('Count it.')
	->setFinal()
	->setProtected()
	->setReturnType('?int') // módszer visszatérési típusa
	->setBody('return count($items ?: $this->items);');

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

Ez a következőket eredményezi:

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

A PHP 8.0 által bevezetett támogatott paraméterek átadhatók a konstruktornak:

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

Ez a következőket eredményezi:

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

A csak olvasható tulajdonságok és osztályok a `setReadOnly()` címen keresztül jelölhetők meg.

------

Ha a hozzáadott tulajdonság, konstans, metódus vagy paraméter már létezik, akkor kivételt dob.

A tagok eltávolítása a `removeProperty()`, `removeConstant()`, `removeMethod()` vagy a `removeParameter()` segítségével történhet.

A már létező `Method`, `Property` vagy `Constant` objektumokat is hozzáadhatja az osztályhoz:

```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);
```

A meglévő metódusokat, tulajdonságokat és konstansokat más névvel klónozhatja a `cloneWithName()` segítségével:

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


Interface vagy Trait .[#toc-interface-or-trait]
-----------------------------------------------

Interfészeket és tulajdonságokat hozhat létre ( [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');
```

Vonások 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;
	}
}
```


Enums .[#toc-enums]
-------------------

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

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

Az esetek skaláris megfelelőit is definiálhatja, hogy létrehozzon egy támogatott enumot:

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

A `addComment()` vagy a `addAttribute()` segítségével minden egyes esethez hozzáadhatunk egy megjegyzést vagy [attribútumokat |#attributes].


Névtelen osztály .[#toc-anonymous-class]
----------------------------------------

Adjuk meg a `null` nevet, é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 funkció .[#toc-global-function]
----------------------------------------

A függvények kódja létrehozza a [GlobalFunction |api:Nette\PhpGenerator\GlobalFunction] osztályt:

```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 szabványnak megfelelő kimenethez.
// echo (new Nette\PhpGenerator\PsrPrinter)->printFunction($function);
```

Eredmény:

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


Zárás .[#toc-closure]
---------------------

A lezárások kódja a [Closure |api:Nette\PhpGenerator\Closure] osztályt fogja létrehozni:

```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 szabványnak megfelelő kimenethez.
// echo (new Nette\PhpGenerator\PsrPrinter)->printClosure($closure);
```

Eredmény:

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


Nyíl funkció .[#toc-arrow-function]
-----------------------------------

A lezárást nyíl funkcióként is kinyomtathatja a nyomtató 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
```


Módszer és funkció aláírása .[#toc-method-and-function-signature]
-----------------------------------------------------------------

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

```php
$method = $class->addMethod('count')
	->addComment('Count it.')
	->setFinal()
	->setProtected()
	->setReturnType('?int');
```

Minden paramétert egy [Parameter |api:Nette\PhpGenerator\Parameter] osztály képvisel. Ismét minden elképzelhető tulajdonságot beállíthat:

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

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

Az úgynevezett variadics paraméterek (vagy akár a splat, spread, ellipszis, kipakolás vagy a három pont operátor) definiálásához használja a `setVariadic()`:

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

Generates:

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


Módszer és funkciótest .[#toc-method-and-function-bodies]
---------------------------------------------------------

A test átadható a `setBody()` metódusnak egyszerre vagy szekvenciálisan (soronként) a `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 helyőrzőket használhat a változók befecskendezésének praktikus módjához.

Egyszerű helytartók `?`

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

Variadic placeholder `...?`

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

A PHP 8 névvel ellátott paramétereket is használhatja a helyőrző használatával. `...?:`

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

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

Helytartó szláv segítségével menekülhet `\?`

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


Nyomtatók és PSR-megfelelőség .[#toc-printers-and-psr-compliance]
-----------------------------------------------------------------

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

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

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

Minden más elemhez képes kódot generálni, és olyan módszereket kínál, mint a `printFunction()`, `printNamespace()`, stb.

Ezenkívül rendelkezésre áll a `PsrPrinter` osztály, amelynek kimenete megfelel a PSR-2 / PSR-12 / PER kódolási stílusnak:

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

Szüksége van a viselkedés finomhangolására az Ön igényei szerint? Hozzon létre saját nyomtatót a `Printer` osztály öröklésével. Ezeket a változókat átkonfigurálhatja:

```php
class MyPrinter extends Nette\PhpGenerator\Printer
{
	// a sor hossza, amely után a sor megszakad.
	public int $wrapLength = 120;
	// behúzás karakter, helyettesíthető szóközökkel
	public string $indentation = "\t";
	// a tulajdonságok közötti üres sorok száma
	public int $linesBetweenProperties = 0;
	// üres sorok száma a metódusok között
	public int $linesBetweenMethods = 2;
	// üres sorok száma az osztályok, függvények és konstansok használati utasításcsoportjai között
	public int $linesBetweenUseTypes = 0;
	// a nyitó zárójel pozíciója függvények és metódusok esetén
	public bool $bracesOnNextLine = true;
	// egy paramétert egy sorba helyezünk, még akkor is, ha attribútummal rendelkezik vagy előléptetve van.
	public bool $singleParameterOnOneLine = false;
	// omits namespaces that do not contain any class or function
	public bool $omitEmptyNamespaces = true;
	// elválasztó a függvények és metódusok jobb oldali zárójel és a visszatérési típus között.
	public string $returnTypeColon = ': ';
}
```

Miben és miért különbözik pontosan a szabványos `Printer` és a `PsrPrinter`? Miért nincs csak egy nyomtató, a `PsrPrinter`, a csomagban?

A szabványos `Printer` úgy formázza a kódot, ahogyan azt az egész Nette-ben tesszük. Mivel a Nette sokkal korábban készült, mint a PSR, és mivel a PSR sok éven át nem időben, hanem néha akár több éves késéssel szállította a szabványokat egy-egy új funkció bevezetésétől a PHP-ben, ez néhány kisebb eltérést eredményezett a [kódolási szabványban |contributing:coding-standard].
A nagyobb különbség csupán a tabulátorok használata a szóközök helyett. Tudjuk, hogy a tabulátorok használatával a projektjeinkben lehetővé tesszük a szélesség beállítását, ami a [látássérült emberek számára elengedhetetlen |contributing:coding-standard#Tabs Instead of Spaces].
Egy példa a kisebb különbségre a függvények és metódusok esetében a görbe zárójel külön sorba helyezése és mindig. A PSR ajánlását logikátlannak látjuk, és a [kód áttekinthetőségének csökkenéséhez vezet |contributing:coding-standard#Wrapping and Braces].


Típusok .[#toc-types]
---------------------

Minden típus vagy union/intersection típus átadható stringként, a natív típusokhoz előre definiált konstansokat is használhat:

```php
use Nette\PhpGenerator\Type;

$member->setType('array'); // vagy Type::Array;
$member->setType('?array'); // or Type::nullable(Type::Array);
$member->setType('array|string'); // or 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()` módszerre is.


Literálisok .[#toc-literals]
----------------------------

A `Literal` segítségével tetszőleges PHP kódot adhat át, például alapértelmezett tulajdonság vagy paraméter értékeket 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)
	{
	}
}
```

A `Literal` oldalnak paramétereket is átadhat, és azt [speciális helyőrzőket |#method-and-function-bodies] használva érvényes PHP-kóddá formázhatja:

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

Az új objektum létrehozását jelképező literál a `new` módszerrel könnyen létrehozható:

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


Attribútumok .[#toc-attributes]
-------------------------------

A PHP 8 attribútumokat minden osztályhoz, metódushoz, tulajdonsághoz, konstanshoz, enum esetekhez, függvényekhez, lezárásokhoz és paraméterekhez hozzáadhatja. [Irodalmi karakterek |#Literals] is használhatók paraméterértékként.

```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,
	) {
	}
}
```


Ingatlan horgok .[#toc-property-hooks]
--------------------------------------

A PHP 8.4-ben bevezetett funkció, a [PropertyHook |api:Nette\PhpGenerator\PropertyHook] osztály által képviselt PropertyHook horgok is definiálhatók a get és set műveletekhez:

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

Ez generálja:

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

Tulajdonságok és tulajdonsághorgok lehetnek absztraktak vagy véglegesek:

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

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


Aszimmetrikus láthatóság .[#toc-asymmetric-visibility]
------------------------------------------------------

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

A láthatóságot vagy a `setVisibility()` metódussal lehet beállítani két paraméterrel, vagy a `setPublic()`, `setProtected()` vagy `setPrivate()` metódussal a `mode` paraméterrel, amely megadja, hogy a láthatóság a tulajdonság megszerzésére vagy beállítására vonatkozik-e a tulajdonság. Az alapértelmezett mód a `'get'`.

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

$class->addProperty('name')
    ->setType('string')
    ->setVisibility('public', 'private'); // public for read, private for write

$class->addProperty('id')
    ->setType('int')
    ->setProtected('set'); // protected for write

echo $class;
```

Ez generálja:

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

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


Namespace .[#toc-namespace]
---------------------------

Az osztályok, tulajdonságok, interfészek és enumok (a továbbiakban osztályok) névterekbe ([PhpNamespace |api:Nette\PhpGenerator\PhpNamespace]) csoportosíthatók:

```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 egy 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, akkor kivételt dob.

Használati utasításokat definiálhat:

```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');
```

A `simplifyName` módszerrel egyszerűsíthet egy teljesen minősített osztály-, függvény- vagy konstansnevet a definiált aliasoknak megfelelően:

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

Ezzel szemben az egyszerűsített osztály-, függvény- vagy konstansnevet a `resolveName` módszerrel alakíthatja át teljes minősítésűvé:

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


Osztálynevek feloldása .[#toc-class-names-resolving]
----------------------------------------------------

**Ha egy osztály egy névtér része, akkor kissé másképp jelenik meg:** minden típus (pl. a típushivatkozások, visszatérési típusok, szülőosztály neve, implementált interfészek, használt tulajdonságok és attribútumok) automatikusan *feloldódik* (hacsak ki nem kapcsolod, lásd alább).
Ez azt jelenti, hogy a definíciókban **teljesen minősített osztályneveket** kell használnia, és ezek helyébe aliasok (a használati záradékok alapján) vagy teljesen minősített nevek lépnek az eredményül kapott kódban:

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

$class = $namespace->addClass('Demo');
$class->addImplement('Foo\A') // egyszerűsödik A
	->addTrait('Bar\AliasedClass'); // AliasedClass-ra fog egyszerűsödni

$method = $class->addMethod('method');
$method->addComment('@return ' . $namespace->simplifyType('Foo\D')); // a megjegyzésekben manuálisan egyszerűsítünk
$method->addParameter('arg')
	->setType('Bar\OtherClass'); // feloldódik \Bar\OtherClass-ra

echo $namespace;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szabványnak megfelelő 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 feloldás így kikapcsolható:

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


PHP Fájlok .[#toc-php-files]
----------------------------

Az osztályok, függvények és névterek PHP fájlokba csoportosíthatók, amelyeket a [PhpFile |api:Nette\PhpGenerator\PhpFile] osztály képvisel:

```php
$file = new Nette\PhpGenerator\PhpFile;
$file->addComment('This file is auto-generated.');
$file->setStrictTypes(); // adds 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 szabványnak megfelelő kimenethez.
// echo (new Nette\PhpGenerator\PsrPrinter)->printFile($file);
```

Eredmény:

```php
<?php

/**
 * This file is auto-generated.
 */

declare(strict_types=1);

namespace Foo;

class A
{
}

function foo()
{
}
```

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


A meglévők szerint generálva .[#toc-generating-according-to-existing-ones]
--------------------------------------------------------------------------

Amellett, hogy az osztályokat és függvényeket a fent leírt API segítségével modellezhetjük, lehetőségünk van arra is, hogy automatikusan generáljuk őket a meglévők alapján:

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

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

// létrehoz egy lezárást a megadottak szerint
$closure = Nette\PhpGenerator\Closure::from(
	function (stdClass $a, $b = null) {},
);
```

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

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

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


Betöltés PHP fájlból .[#toc-loading-from-php-file]
--------------------------------------------------

A függvényeket, osztályokat, interfészeket és enumokat közvetlenül egy PHP kódsorozatból is betöltheti. Például így hozzuk létre a `ClassType` objektumot:

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

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

Az osztályok PHP kódból történő betöltésekor a metódus testén kívüli egysoros megjegyzéseket figyelmen kívül hagyjuk (pl. tulajdonságok stb. esetén), mivel ez a könyvtár nem rendelkezik API-val ezek kezelésére.

A teljes PHP-fájlt közvetlenül is betöltheti, amely tetszőleges számú osztályt, függvényt vagy akár több névteret is tartalmazhat:

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

A kezdeti fájlkommentár és a `strict_types` nyilatkozat is betöltődik. Másrészt minden más globális kódot figyelmen kívül hagyunk.

Ehhez telepíteni kell a `nikic/php-parser` oldalt.

.[note]
Ha fájlokban lévő globális kódot vagy a metódusok testében lévő egyes utasításokat kell manipulálnia, jobb, ha közvetlenül a `nikic/php-parser` könyvtárat használja.


Osztály Manipulátor .[#toc-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);
```

A `inheritMethod()` metódus egy metódust másol át egy szülő osztályból vagy egy implementált interfészből az osztályodba. 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('...');
```

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

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

A `implement()` módszer automatikusan megvalósítja az adott interfész vagy absztrakt osztály összes metódusát és tulajdonságát:

```php
$manipulator->implement(SomeInterface::class);
// Most az osztályod megvalósítja a SomeInterface-t és tartalmazza annak összes metódusát.
```


Változók Dumper .[#toc-variables-dumper]
----------------------------------------

A Dumper egy változó egy elemezhető PHP-string reprezentációját adja vissza. Jobb és egyértelműbb kimenetet biztosít, mint a natív `var_export()` függvény.

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

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

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


Kompatibilitási táblázat .[#toc-compatibility-table]
----------------------------------------------------

A PhpGenerator 4.1 kompatibilis a PHP 8.0 és 8.4 között.

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

PHP kód generátor

Olyan eszközt keres, amellyel PHP kódot generálhat osztályokhoz, függvényekhez vagy teljes fájlokhoz?
  • Támogatja az összes legújabb PHP funkciót (mint például a property hooks, enums, attribútumok, stb.)
  • Lehetővé teszi a meglévő osztályok egyszerű módosítását
  • PSR-12 / PER kódolási stílusnak megfelelő kimenet
  • Kiforrott, stabil és széles körben használt könyvtár

Telepítés

Töltse le és telepítse a csomagot a Composer segítségével:

composer require nette/php-generator

A PHP-kompatibilitásról lásd a táblázatot.

Osztályok

Kezdjük egy egyszerű példával az osztály generálására a ClassType használatával:

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

$class
	->setFinal()
	->setExtends(ParentClass::class)
	->addImplement(Countable::class)
	->addComment("Description of class.\nSecond line\n")
	->addComment('@property-read Nette\Forms\Form $form');

// PHP kód generálásához egyszerűen csak öntsd stringre, vagy használd az echo-t:
echo $class;

A következő eredményt adja ki:

/**
 * Description of class.
 * Second line
 *
 * @property-read Nette\Forms\Form $form
 */
final class Demo extends ParentClass implements Countable
{
}

A kód generálásához használhatunk nyomtatót is, amelyet a echo $class címmel ellentétben tovább konfigurálhatunk:

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

Konstanciákat (class Constant) és tulajdonságokat (class Property) adhatunk hozzá:

$class->addConstant('ID', 123)
	->setProtected() // konstans láthatóság
	->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'

Ez 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('Count it.')
	->setFinal()
	->setProtected()
	->setReturnType('?int') // módszer visszatérési típusa
	->setBody('return count($items ?: $this->items);');

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

Ez a következőket eredményezi:

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

A PHP 8.0 által bevezetett támogatott paraméterek átadhatók a konstruktornak:

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

Ez a következőket eredményezi:

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

A csak olvasható tulajdonságok és osztályok a setReadOnly() címen keresztül jelölhetők meg.


Ha a hozzáadott tulajdonság, konstans, metódus vagy paraméter már létezik, akkor kivételt dob.

A tagok eltávolítása a removeProperty(), removeConstant(), removeMethod() vagy a removeParameter() segítségével történhet.

A már létező Method, Property vagy Constant objektumokat is hozzáadhatja az osztályhoz:

$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);

A meglévő metódusokat, tulajdonságokat és konstansokat más névvel klónozhatja a cloneWithName() segítségével:

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

Interface vagy Trait

Interfészeket és tulajdonságokat hozhat létre ( InterfaceType és TraitType osztályok):

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

Vonások 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;
	}
}

Enums

A PHP 8.1 által hozott enumokat ( EnumType osztály) könnyen létrehozhatod:

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

Az esetek skaláris megfelelőit is definiálhatja, hogy létrehozzon egy támogatott enumot:

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

A addComment() vagy a addAttribute() segítségével minden egyes esethez hozzáadhatunk egy megjegyzést vagy attribútumokat.

Névtelen osztály

Adjuk meg a null nevet, é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 funkció

A függvények kódja létrehozza a GlobalFunction osztályt:

$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 szabványnak megfelelő kimenethez.
// echo (new Nette\PhpGenerator\PsrPrinter)->printFunction($function);

Eredmény:

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

Zárás

A lezárások kódja a Closure osztályt fogja létrehozni:

$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 szabványnak megfelelő kimenethez.
// echo (new Nette\PhpGenerator\PsrPrinter)->printClosure($closure);

Eredmény:

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

Nyíl funkció

A lezárást nyíl funkcióként is kinyomtathatja a nyomtató 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

Módszer és funkció aláírása

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

$method = $class->addMethod('count')
	->addComment('Count it.')
	->setFinal()
	->setProtected()
	->setReturnType('?int');

Minden paramétert egy Parameter osztály képvisel. Ismét minden elképzelhető tulajdonságot beállíthat:

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

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

Az úgynevezett variadics paraméterek (vagy akár a splat, spread, ellipszis, kipakolás vagy a három pont operátor) definiálásához használja a setVariadic():

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

Generates:

function count(...$items)
{
}

Módszer és funkciótest

A test átadható a setBody() metódusnak egyszerre vagy szekvenciálisan (soronként) a 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 helyőrzőket használhat a változók befecskendezésének praktikus módjához.

Egyszerű helytartók ?

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

Variadic placeholder ...?

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

Eredmény:

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

A PHP 8 névvel ellátott paramétereket is használhatja a helyőrző használatával. ...?:

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

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

Helytartó szláv segítségével menekülhet \?

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

Nyomtatók és PSR-megfelelőség

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

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

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

Minden más elemhez képes kódot generálni, és olyan módszereket kínál, mint a printFunction(), printNamespace(), stb.

Ezenkívül rendelkezésre áll a PsrPrinter osztály, amelynek kimenete megfelel a PSR-2 / PSR-12 / PER kódolási stílusnak:

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

Szüksége van a viselkedés finomhangolására az Ön igényei szerint? Hozzon létre saját nyomtatót a Printer osztály öröklésével. Ezeket a változókat átkonfigurálhatja:

class MyPrinter extends Nette\PhpGenerator\Printer
{
	// a sor hossza, amely után a sor megszakad.
	public int $wrapLength = 120;
	// behúzás karakter, helyettesíthető szóközökkel
	public string $indentation = "\t";
	// a tulajdonságok közötti üres sorok száma
	public int $linesBetweenProperties = 0;
	// üres sorok száma a metódusok között
	public int $linesBetweenMethods = 2;
	// üres sorok száma az osztályok, függvények és konstansok használati utasításcsoportjai között
	public int $linesBetweenUseTypes = 0;
	// a nyitó zárójel pozíciója függvények és metódusok esetén
	public bool $bracesOnNextLine = true;
	// egy paramétert egy sorba helyezünk, még akkor is, ha attribútummal rendelkezik vagy előléptetve van.
	public bool $singleParameterOnOneLine = false;
	// omits namespaces that do not contain any class or function
	public bool $omitEmptyNamespaces = true;
	// elválasztó a függvények és metódusok jobb oldali zárójel és a visszatérési típus között.
	public string $returnTypeColon = ': ';
}

Miben és miért különbözik pontosan a szabványos Printer és a PsrPrinter? Miért nincs csak egy nyomtató, a PsrPrinter, a csomagban?

A szabványos Printer úgy formázza a kódot, ahogyan azt az egész Nette-ben tesszük. Mivel a Nette sokkal korábban készült, mint a PSR, és mivel a PSR sok éven át nem időben, hanem néha akár több éves késéssel szállította a szabványokat egy-egy új funkció bevezetésétől a PHP-ben, ez néhány kisebb eltérést eredményezett a kódolási szabványban. A nagyobb különbség csupán a tabulátorok használata a szóközök helyett. Tudjuk, hogy a tabulátorok használatával a projektjeinkben lehetővé tesszük a szélesség beállítását, ami a látássérült emberek számára elengedhetetlen. Egy példa a kisebb különbségre a függvények és metódusok esetében a görbe zárójel külön sorba helyezése és mindig. A PSR ajánlását logikátlannak látjuk, és a kód áttekinthetőségének csökkenéséhez vezet.

Típusok

Minden típus vagy union/intersection típus átadható stringként, a natív típusokhoz előre definiált konstansokat is használhat:

use Nette\PhpGenerator\Type;

$member->setType('array'); // vagy Type::Array;
$member->setType('?array'); // or Type::nullable(Type::Array);
$member->setType('array|string'); // or 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() módszerre is.

Literálisok

A Literal segítségével tetszőleges PHP kódot adhat át, például alapértelmezett tulajdonság vagy paraméter értékeket 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)
	{
	}
}

A Literal oldalnak paramétereket is átadhat, és azt speciális helyőrzőket használva érvényes PHP-kóddá formázhatja:

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

Az új objektum létrehozását jelképező literál a new módszerrel könnyen létrehozható:

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

Attribútumok

A PHP 8 attribútumokat minden osztályhoz, metódushoz, tulajdonsághoz, konstanshoz, enum esetekhez, függvényekhez, lezárásokhoz és paraméterekhez hozzáadhatja. Irodalmi karakterek is használhatók paraméterértékként.

$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,
	) {
	}
}

Ingatlan horgok

A PHP 8.4-ben bevezetett funkció, a PropertyHook osztály által képviselt PropertyHook horgok is definiálhatók a get és set műveletekhez:

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

Ez generálja:

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

Tulajdonságok és tulajdonsághorgok lehetnek absztraktak vagy véglegesek:

$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 a tulajdonságok aszimmetrikus láthatóságát. Különböző hozzáférési szinteket állíthat be az olvasáshoz és az íráshoz.

A láthatóságot vagy a setVisibility() metódussal lehet beállítani két paraméterrel, vagy a setPublic(), setProtected() vagy setPrivate() metódussal a mode paraméterrel, amely megadja, hogy a láthatóság a tulajdonság megszerzésére vagy beállítására vonatkozik-e a tulajdonság. Az alapértelmezett mód a 'get'.

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

$class->addProperty('name')
    ->setType('string')
    ->setVisibility('public', 'private'); // public for read, private for write

$class->addProperty('id')
    ->setType('int')
    ->setProtected('set'); // protected for write

echo $class;

Ez generálja:

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

    protected(set) int $id;
}

Namespace

Az osztályok, tulajdonságok, interfészek és enumok (a továbbiakban osztályok) névterekbe (PhpNamespace) csoportosíthatók:

$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 egy 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, akkor kivételt dob.

Használati utasításokat definiálhat:

// 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');

A simplifyName módszerrel egyszerűsíthet egy teljesen minősített osztály-, függvény- vagy konstansnevet a definiált aliasoknak megfelelően:

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

Ezzel szemben az egyszerűsített osztály-, függvény- vagy konstansnevet a resolveName módszerrel alakíthatja át teljes minősítésűvé:

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

Osztálynevek feloldása

Ha egy osztály egy névtér része, akkor kissé másképp jelenik meg: minden típus (pl. a típushivatkozások, visszatérési típusok, szülőosztály neve, implementált interfészek, használt tulajdonságok és attribútumok) automatikusan feloldódik (hacsak ki nem kapcsolod, lásd alább). Ez azt jelenti, hogy a definíciókban teljesen minősített osztályneveket kell használnia, és ezek helyébe aliasok (a használati záradékok alapján) vagy teljesen minősített nevek lépnek az eredményül kapott kódban:

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

$class = $namespace->addClass('Demo');
$class->addImplement('Foo\A') // egyszerűsödik A
	->addTrait('Bar\AliasedClass'); // AliasedClass-ra fog egyszerűsödni

$method = $class->addMethod('method');
$method->addComment('@return ' . $namespace->simplifyType('Foo\D')); // a megjegyzésekben manuálisan egyszerűsítünk
$method->addParameter('arg')
	->setType('Bar\OtherClass'); // feloldódik \Bar\OtherClass-ra

echo $namespace;

// vagy használja a PsrPrintert a PSR-2 / PSR-12 / PER szabványnak megfelelő 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 feloldás így kikapcsolható:

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

PHP Fájlok

Az osztályok, függvények és névterek PHP fájlokba csoportosíthatók, amelyeket a PhpFile osztály képvisel:

$file = new Nette\PhpGenerator\PhpFile;
$file->addComment('This file is auto-generated.');
$file->setStrictTypes(); // adds 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 szabványnak megfelelő kimenethez.
// echo (new Nette\PhpGenerator\PsrPrinter)->printFile($file);

Eredmény:

<?php

/**
 * This file is auto-generated.
 */

declare(strict_types=1);

namespace Foo;

class A
{
}

function foo()
{
}

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

A meglévők szerint generálva

Amellett, hogy az osztályokat és függvényeket a fent leírt API segítségével modellezhetjük, lehetőségünk van arra is, hogy automatikusan generáljuk őket a meglévők alapján:

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

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

// létrehoz egy lezárást a megadottak szerint
$closure = Nette\PhpGenerator\Closure::from(
	function (stdClass $a, $b = null) {},
);

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

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

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

Betöltés PHP fájlból

A függvényeket, osztályokat, interfészeket és enumokat közvetlenül egy PHP kódsorozatból is betöltheti. Például így hozzuk létre a ClassType objektumot:

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

	class Demo
	{
		public $foo;
	}
	XX);

Az osztályok PHP kódból történő betöltésekor a metódus testén kívüli egysoros megjegyzéseket figyelmen kívül hagyjuk (pl. tulajdonságok stb. esetén), mivel ez a könyvtár nem rendelkezik API-val ezek kezelésére.

A teljes PHP-fájlt közvetlenül is betöltheti, amely tetszőleges számú osztályt, függvényt vagy akár több névteret is tartalmazhat:

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

A kezdeti fájlkommentár és a strict_types nyilatkozat is betöltődik. Másrészt minden más globális kódot figyelmen kívül hagyunk.

Ehhez telepíteni kell a nikic/php-parser oldalt.

Ha fájlokban lévő globális kódot vagy a metódusok testében lévő egyes utasításokat kell manipulálnia, jobb, ha közvetlenül a nikic/php-parser könyvtárat használja.

Osztály Manipulátor

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

A inheritMethod() metódus egy metódust másol át egy szülő osztályból vagy egy implementált interfészből az osztályodba. 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('...');

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

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

A implement() módszer automatikusan megvalósítja az adott interfész vagy absztrakt osztály összes metódusát és tulajdonságát:

$manipulator->implement(SomeInterface::class);
// Most az osztályod megvalósítja a SomeInterface-t és tartalmazza annak összes metódusát.

Változók Dumper

A Dumper egy változó egy elemezhető PHP-string reprezentációját adja vissza. Jobb és egyértelműbb kimenetet biztosít, mint a natív var_export() függvény.

$dumper = new Nette\PhpGenerator\Dumper;

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

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

Kompatibilitási táblázat

A PhpGenerator 4.1 kompatibilis a PHP 8.0 és 8.4 között.