nette/php-generator

🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.1 features.

v3.0.1 2017-07-11 19:07 UTC

README

Downloads this Month Build Status Coverage Status Latest Stable Version License

Generate PHP code, classes, namespaces etc. with a simple programmatical API.

Usage is very easy. Install it using Composer:

composer require nette/php-generator

The last stable release requires PHP version 5.6 or newer (is compatible with PHP 7.0 and 7.1). The dev-master version requires PHP 7.0.

Examples

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

$class->addConstant('ID', 123);

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

$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 = []

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;

	const ID = 123;

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

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

}

PHP Generator supports all new PHP 7.1 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);
	}

}

Literals

You can pass any PHP code to property or parameter default values via Nette\PhpGenerator\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');
$class->setType('trait'); // or 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

$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

$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 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('$a = strlen(?, ?);', [$str, $num]);
$function->addBody('return $a \? 10 : ?;', [$num]); // escaping
echo $function;

Result:

function foo()
{
	$a = strlen('any string', 3);
	return $a ? 10 : 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);
}

Namespace

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

}

Factories

Another common use case is to create class or method form 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) {}
);