All Projects → nette → Php Generator

nette / Php Generator

Licence: other
🐘 Generates neat PHP code for you. Supports new PHP 8.0 features.

Projects that are alternatives of or similar to Php Generator

Bootstrap
🅱 The simple way to configure and bootstrap your Nette application.
Stars: ✭ 524 (-58.54%)
Mutual labels:  nette, nette-framework
Utils
🛠 Lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.
Stars: ✭ 1,158 (-8.39%)
Mutual labels:  nette, nette-framework
Latte
☕ Latte: the intuitive and fast template engine for those who want the most secure PHP sites.
Stars: ✭ 616 (-51.27%)
Mutual labels:  nette, nette-framework
Tester
Tester: enjoyable unit testing in PHP with code coverage reporter. 🍏🍏🍎🍏
Stars: ✭ 281 (-77.77%)
Mutual labels:  nette, nette-framework
Mobile Detect
Extension for detecting mobile devices, managing mobile view types, redirect to mobile version for Nette Framework (2.4+)
Stars: ✭ 19 (-98.5%)
Mutual labels:  nette, nette-framework
Mail
📧 Handy email creation and transfer library for PHP with both text and MIME-compliant support.
Stars: ✭ 288 (-77.22%)
Mutual labels:  nette, nette-framework
Neon
🍸 Encodes and decodes NEON file format.
Stars: ✭ 674 (-46.68%)
Mutual labels:  nette, nette-framework
command-line
⌨ Command line options and arguments parser.
Stars: ✭ 35 (-97.23%)
Mutual labels:  nette, nette-framework
Guzzlette
🌀 Guzzle integration into Nette Framework (@nette)
Stars: ✭ 19 (-98.5%)
Mutual labels:  nette, nette-framework
Finder
🔍 Finder: find files and directories with an intuitive API.
Stars: ✭ 765 (-39.48%)
Mutual labels:  nette, nette-framework
Forms
📝 Generating, validating and processing secure forms in PHP. Handy API, fully customizable, server & client side validation and mature design.
Stars: ✭ 272 (-78.48%)
Mutual labels:  nette, nette-framework
Middlewares
💥 Middlewares / Relay / PSR-7 support to Nette Framework (@nette)
Stars: ✭ 13 (-98.97%)
Mutual labels:  nette, nette-framework
psr7-http-message
💫 PSR #7 [HTTP Message Interface] to Nette Framework (@nette)
Stars: ✭ 17 (-98.66%)
Mutual labels:  nette, nette-framework
Schema
📐 Validating data structures against a given Schema.
Stars: ✭ 359 (-71.6%)
Mutual labels:  nette, nette-framework
migrations
🏃 Doctrine Migrations for Nette Framework
Stars: ✭ 36 (-97.15%)
Mutual labels:  nette, nette-framework
Di
💎 Flexible, compiled and full-featured Dependency Injection Container with perfectly usable autowiring and support for all new PHP 7 features.
Stars: ✭ 645 (-48.97%)
Mutual labels:  nette, nette-framework
playground
📚 Examples, projects, webprojects, skeletons for Nette Framework (@nette) from community members. Included @contributte @apitte @nettrine projects.
Stars: ✭ 23 (-98.18%)
Mutual labels:  nette, nette-framework
codeception
▶️ Integration of Nette Framework to Codeception.
Stars: ✭ 27 (-97.86%)
Mutual labels:  nette, nette-framework
Robot Loader
🍀 RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.
Stars: ✭ 690 (-45.41%)
Mutual labels:  nette, nette-framework
Flash Messages
Flash messages handler for Nette Framework (2.4+)
Stars: ✭ 8 (-99.37%)
Mutual labels:  nette, nette-framework

Nette PHP Generator

Downloads this Month Tests Coverage Status Latest Stable Version License

Introduction

Do you need to generate PHP code of classes, functions, namespaces, etc.? This library with a friendly API will help you.

Documentation can be found on the website.

Support Me

Do you like PHP Generator? Are you looking forward to the new features?

Buy me a coffee

Thank you!

Installation

composer require nette/php-generator
  • PhpGenerator 4.0 is compatible with PHP 8.0
  • PhpGenerator 3.2 – 3.5 is compatible with PHP 7.1 to 8.0
  • PhpGenerator 3.1 is compatible with PHP 7.1 to 7.3
  • PhpGenerator 3.0 is compatible with PHP 7.0 to 7.3
  • PhpGenerator 2.6 is compatible with PHP 5.6 to 7.3

Classes

Let's start with a straightforward example of generating class using ClassType:

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

$class
	->setFinal()
	->setExtends(ParentClass::class)
	->addImplement(Countable::class)
	->addTrait(Nette\SmartObject::class)
	->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
 */
final class Demo extends ParentClass implements Countable
{
	use Nette\SmartObject;
}

We can also use a printer to generate the code, which, unlike echo $class, we will be able to further configure:

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

We can add constants (Constant) and properties (Property):

$class->addConstant('ID', 123)
	->setPrivate(); // constant visiblity

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

$class->addProperty('list')
	->setType('array')
	->setNullable()
	->setInitialized(); // prints '= null'

It generates:

private const ID = 123;

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

public ?array $list = null;

And we can add methods with parameters:

$method = $class->addMethod('count')
	->addComment('Count it.')
	->addComment('@return int')
	->setFinal()
	->setProtected()
	->setReturnType('int') // method return type
	->setReturnNullable() // nullable return type
	->setBody('return count($items ?: $this->items);');

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

It results in:

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

Promoted parameters introduced by PHP 8.0 can be passed to the constructor:

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

It results in:

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

If the property, constant, method or parameter already exist, it will be overwritten.

Members can be removed using removeProperty(), removeConstant(), removeMethod() or removeParameter().

You can also add existing Method, Property or Constant objects to the class:

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

You can clone existing methods, properties and constants with a different name using cloneWithName():

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

Types

Each type or union type can be passed as a string, you can also use predefined constants for native types:

use Nette\PhpGenerator\Type;

$member->setType('array');
$member->setType(Type::ARRAY);
$member->setType('array|string');
$member->setType(null); // removes type

The same applies to the method setReturnType().

Tabs versus Spaces

The generated code uses tabs for indentation. If you want to have the output compatible with PSR-2 or PSR-12, use PsrPrinter:

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

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

Interface or Trait

You can create interfaces and traits in a similar way, just change the type:

$class = new Nette\PhpGenerator\ClassType('DemoInterface');
$class->setInterface();
// or $class->setTrait();

Literals

You can pass any PHP code to property or parameter default values via Literal:

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;

Result:

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

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

Using Traits

$class = new Nette\PhpGenerator\ClassType('Demo');
$class->addTrait('SmartObject');
$class->addTrait('MyTrait', ['sayHello as protected']);
echo $class;

Result:

class Demo
{
	use SmartObject;
	use MyTrait {
		sayHello as protected;
	}
}

Anonymous Class

Give null as the name and you have an 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 functions will generate class GlobalFunction:

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

// or use PsrPrinter for output compatible with PSR-2 / PSR-12
// echo (new Nette\PhpGenerator\PsrPrinter)->printFunction($function);

Result:

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

Closure

Code of closures will generate class Closure:

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

// or use PsrPrinter for output compatible with PSR-2 / PSR-12
// echo (new Nette\PhpGenerator\PsrPrinter)->printClosure($closure);

Result:

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

Arrow Function

You can also print closure as arrow function using printer:

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

// or use PsrPrinter for output compatible with PSR-2 / PSR-12
echo (new Nette\PhpGenerator\Printer)->printArrowFunction($closure);

Result:

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

Attributes

You can add PHP 8 attributes to all classes, methods, properties, constants, functions, closures and parameters.

$class = new Nette\PhpGenerator\ClassType('Demo');
$class->addAttribute('Deprecated');

$class->addProperty('list')
	->addAttribute('WithArguments', [1, 2]);

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

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

echo $class;

Result:

#[Deprecated]
class Demo
{
	#[WithArguments(1, 2)]
	public $list;


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

Method and Function Body Generator

The body can be passed to the setBody() method at once or sequentially (line by line) by repeatedly calling addBody():

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

Result

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

You can use special placeholders for handy way to inject variables.

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

You can also use PHP 8 named parameters using placeholder ...?:

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

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

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

Classes, traits and interfaces (hereinafter classes) can be grouped into namespaces (PhpNamespace):

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

// create new classes in the namespace
$class = $namespace->addClass('Task');
$interface = $namespace->addInterface('Countable');
$trait = $namespace->addTrait('NameAware');

// or insert an existing class into the namespace
$class = new Nette\PhpGenerator\ClassType('Task');
$namespace->add($class);

If the class already exists, it will be overwritten.

You can define use-statements:

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

Class Names Resolving

When the class is part of the namespace, it is rendered slightly differently: all types (ie. type hints, return types, parent class name, implemented interfaces, used traits and attributes) are automatically resolved (unless you turn it off, see below). It means that you have to use full class names in definitions and they will be replaced with aliases (according to the use-statements) 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') // it will resolve to A
	->addTrait('Bar\AliasedClass'); // it will resolve to AliasedClass

$method = $class->addMethod('method');
$method->addComment('@return ' . $namespace->unresolveName('Foo\D')); // in comments resolve manually
$method->addParameter('arg')
	->setType('Bar\OtherClass'); // it will resolve to \Bar\OtherClass

echo $namespace;

// or use PsrPrinter for output compatible with PSR-2 / PSR-12
// echo (new Nette\PhpGenerator\PsrPrinter)->printNamespace($namespace);

Result:

namespace Foo;

use Bar\AliasedClass;

class Demo implements A
{
	use AliasedClass;

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

Auto-resolving can be turned off this way:

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

PHP Files

Classes and namespaces can be grouped into PHP files represented by the class PhpFile:

$file = new Nette\PhpGenerator\PhpFile;
$file->addComment('This file is auto-generated.');
$file->setStrictTypes(); // adds declare(strict_types=1)

$namespace = $file->addNamespace('Foo');
$class = $namespace->addClass('A');
$class->addMethod('hello');

// or insert an existing namespace into the file
// $file->addNamespace(new Nette\PhpGenerator\PhpNamespace('Foo'));

echo $file;

// or use PsrPrinter for output compatible with PSR-2 / PSR-12
// echo (new Nette\PhpGenerator\PsrPrinter)->printFile($file);

Result:

<?php

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

declare(strict_types=1);

namespace Foo;

class A
{
	public function hello()
	{
	}
}

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

Method bodies are empty by default. If you want to load them as well, use this way (it requires nikic/php-parser to be installed):

$class = Nette\PhpGenerator\ClassType::withBodiesFrom(MyClass::class);

$function = Nette\PhpGenerator\GlobalFunction::withBodyFrom('dump');

Variables Dumper

The Dumper returns a parsable PHP string representation of a variable. Provides better and clearer output that native functon var_export().

$dumper = new Nette\PhpGenerator\Dumper;

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

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

Custom Printer

Need to customize printer behavior? Create your own by inheriting the Printer class. You can reconfigure these variables:

class MyPrinter extends Nette\PhpGenerator\Printer
{
	protected $indentation = "\t";
	protected $linesBetweenProperties = 0;
	protected $linesBetweenMethods = 1;
	protected $returnTypeColon = ': ';
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].