Nette PHP Generator
Introduction
Generate PHP code, classes, namespaces etc. with a simple programmatical API.
Documentation can be found on the website.
If you like Nette, please make a donation now. Thank you!
Installation
The recommended way to install is via Composer:
composer require nette/php-generator
- v2.6 requires PHP 5.6 or newer (is compatible up to 7.2)
- v3.0 requires PHP 7.0 or newer (is compatible up to 7.2)
- v3.1 requires PHP 7.1 or newer (is compatible up to 7.2)
Usage
Usage is very easy. Let's start with a straightforward example of generating class:
$class = new Nette\PhpGenerator\ClassType('Demo'); $class ->setAbstract() ->setFinal() ->setExtends('ParentClass') ->addImplement('Countable') ->addTrait('Nette\SmartObject') ->addComment("Description of class.\nSecond line\n") ->addComment('@property-read Nette\Forms\Form $form'); // to generate PHP code simply cast to string or use echo: echo $class;
It will render this result:
/** * Description of class. * Second line * * @property-read Nette\Forms\Form $form */ abstract final class Demo extends ParentClass implements Countable { use Nette\SmartObject; }
We can add constants and properties:
$class->addConstant('ID', 123); $class->addProperty('items', [1, 2, 3]) ->setVisibility('private') ->setStatic() ->addComment('@var int[]');
It generates:
const ID = 123; /** @var int[] */ private static $items = [1, 2, 3];
And we can add methods with parameters:
$method = $class->addMethod('count') ->addComment('Count it.') ->addComment('@return int') ->setFinal() ->setVisibility('protected') ->setBody('return count($items ?: $this->items);'); $method->addParameter('items', []) // $items = [] ->setReference() // &$items = [] ->setTypeHint('array'); // array &$items = []
It results in:
/** * Count it. * @return int */ final protected function count(array &$items = []) { return count($items ?: $this->items); }
PHP Generator supports all new PHP 7.2 features:
$class = new Nette\PhpGenerator\ClassType('Demo'); $class->addConstant('ID', 123) ->setVisibility('private'); // constant visiblity $method = $class->addMethod('getValue') ->setReturnType('int') // method return type ->setReturnNullable() // nullable return type ->setBody('return count($this->items);'); $method->addParameter('id') ->setTypeHint('int') // scalar type hint ->setNullable(); // nullable type hint echo $class;
Result:
class Demo { private const ID = 123; public function getValue(?int $id): ?int { return count($this->items); } }
Tabs versus spaces
The generated code uses tabs for indentation, which makes it very easy to change it to any number of spaces:
use Nette\PhpGenerator\Helpers; $class = new Nette\PhpGenerator\ClassType('Demo'); // ... echo Helpers::tabsToSpaces((string) $class); // 4 spaces indentation echo Helpers::tabsToSpaces((string) $class, 2); // 2 spaces indentation
Literals
You can pass any PHP code to property or parameter default values via PhpLiteral:
use Nette\PhpGenerator\PhpLiteral; $class = new Nette\PhpGenerator\ClassType('Demo'); $class->addProperty('foo', new PhpLiteral('Iterator::SELF_FIRST')); $class->addMethod('bar') ->addParameter('id', new PhpLiteral('1 + 2')); echo $class;
Result:
class Demo { public $foo = Iterator::SELF_FIRST; public function bar($id = 1 + 2) { } }
Interface or Trait
$class = new Nette\PhpGenerator\ClassType('DemoInterface'); $class->setType('interface'); // or $class->setType('trait');
Trait Resolutions and Visibility
$class = new Nette\PhpGenerator\ClassType('Demo'); $class->addTrait('SmartObject', ['sayHello as protected']); echo $class;
Result:
class Demo { use SmartObject { sayHello as protected; } }
Anonymous Class
$class = new Nette\PhpGenerator\ClassType(null); $class->addMethod('__construct') ->addParameter('foo'); echo '$obj = new class ($val) ' . $class . ';';
Result:
$obj = new class ($val) { public function __construct($foo) { } };
Global Function
Code of function:
$function = new Nette\PhpGenerator\GlobalFunction('foo'); $function->setBody('return $a + $b;'); $function->addParameter('a'); $function->addParameter('b'); echo $function;
Result:
function foo($a, $b) { return $a + $b; }
Closure
Code of closure:
$closure = new Nette\PhpGenerator\Closure; $closure->setBody('return $a + $b;'); $closure->addParameter('a'); $closure->addParameter('b'); $closure->addUse('c') ->setReference(); echo $closure;
Result:
function ($a, $b) use (&$c) { return $a + $b; }
Method and Function Body Generator
You can use special placeholders for handy way to generate method or function body.
Simple placeholders:
$str = 'any string'; $num = 3; $function = new Nette\PhpGenerator\GlobalFunction('foo'); $function->addBody('return strlen(?, ?);', [$str, $num]); echo $function;
Result:
function foo() { return strlen('any string', 3); }
Variadic placeholder:
$items = [1, 2, 3]; $function = new Nette\PhpGenerator\GlobalFunction('foo'); $function->setBody('myfunc(...?);', [$items]); echo $function;
Result:
function foo() { myfunc(1, 2, 3); }
Escape placeholder using slash:
$num = 3; $function = new Nette\PhpGenerator\GlobalFunction('foo'); $function->addParameter('a'); $function->addBody('return $a \? 10 : ?;', [$num]); echo $function;
Result:
function foo($a) { return $a ? 10 : 3; }
Namespace
Namespaces may include use statements in addition to classes, interfaces, or traits. These statements are used when generating code, so use full class names in the definitions and they will be replace with aliases or fully qualified names in the resulting code.
$namespace = new Nette\PhpGenerator\PhpNamespace('Foo'); $namespace->addUse('Bar\AliasedClass'); $class = $namespace->addClass('Demo'); $class->addImplement('Foo\A') // resolves to A ->addTrait('Bar\AliasedClass'); // resolves to AliasedClass $method = $class->addMethod('method'); $method->addParameter('arg') ->setTypeHint('Bar\OtherClass'); // resolves to \Bar\OtherClass echo $namespace;
Result:
namespace Foo; use Bar\AliasedClass; class Demo implements A { use AliasedClass; public function method(\Bar\OtherClass $arg) { } }
Generate using Reflection
Another common use case is to create class or method based on existing ones:
$class = Nette\PhpGenerator\ClassType::from(PDO::class); $function = Nette\PhpGenerator\GlobalFunction::from('trim'); $closure = Nette\PhpGenerator\Closure::from( function (stdClass $a, $b = null) {} );