• Stars
    star
    1,978
  • Rank 22,383 (Top 0.5 %)
  • Language
    PHP
  • License
    Other
  • Created about 10 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🐘 Generates neat PHP code for you. Supports new PHP 8.3 features.

Nette PHP Generator Latest Stable Version Downloads this Month

βœ… Need to generate PHP code for classes, functions, PHP files, etc.?
βœ… Supports all the latest PHP features like enums, attributes, etc.
βœ… Allows you to easily modify existing classes
βœ… PSR-12 compliant output
βœ… Highly mature, stable, and widely used library

Installation

composer require nette/php-generator

For PHP compatibility, see the table. Documentation even for older versions can be found on the library's website.

Support Me

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

Buy me a coffee

Thank you!

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

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 (class Constant) and properties (class Property):

$class->addConstant('ID', 123)
	->setProtected() // constant visiblity
	->setType('int')
	->setFinal();

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

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

It generates:

final protected const int ID = 123;

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

public ?array $list = null;

And we can add methods:

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

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

It results in:

/**
 * Count it.
 */
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 = [],
) {
}

Readonly properties and classes can be marked via setReadOnly().


If the added property, constant, method or parameter already exist, it throws exception.

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

Interface or Trait

You can create interfaces and traits (classes InterfaceType and TraitType):

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

Using traits:

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

Result:

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

Enums

You can easily create the enums that PHP 8.1 brings (class EnumType):

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

echo $enum;

Result:

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

You can also define scalar equivalents for cases to create a backed enum:

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

It is possible to add a comment or attributes to each case using addComment() or addAttribute().

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 conforming to 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 conforming to 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('$a + $b');
$closure->addParameter('a');
$closure->addParameter('b');

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

Result:

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

Method and Function Signature

Methods are represented by the class Method. You can set visibility, return value, add comments, [attributes|#Attributes] etc:

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

Each parameter is represented by a class Parameter. Again, you can set every conceivable property:

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

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

To define the so-called variadics parameters (or also the splat, spread, ellipsis, unpacking or three dots operator), use setVariadics():

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

Generates:

function count(...$items)
{
}

Method and Function Body

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 substr(?, ?);', [$str, $num]);
echo $function;

Result:

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;

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

Printers and PSR Compliance

The Printer class is used to generate PHP code:

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

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

It can generate code for all other elements, offering methods such as printFunction(), printNamespace(), etc.

Additionally, the PsrPrinter class is available, whose output is in compliance with the PSR-2 / PSR-12 / PER coding style:

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

Need to fine-tune behavior to your needs? Create your own printer by inheriting from the Printer class. You can reconfigure these variables:

class MyPrinter extends Nette\PhpGenerator\Printer
{
	// length of the line after which the line will break
	public int $wrapLength = 120;
	// indentation character, can be replaced with a sequence of spaces
	public string $indentation = "\t";
	// number of blank lines between properties
	public int $linesBetweenProperties = 0;
	// number of blank lines between methods
	public int $linesBetweenMethods = 2;
	// number of blank lines between groups of use statements for classes, functions, and constants
	public int $linesBetweenUseTypes = 0;
	// position of the opening brace for functions and methods
	public bool $bracesOnNextLine = true;
	// place one parameter in one line, even if it has an attribute or is promoted
	public bool $singleParameterOnOneLine = false;
	// separator between the right parenthesis and return type of functions and methods
	public string $returnTypeColon = ': ';
}

How and why exactly does the standard Printer and PsrPrinter differ? Why isn't there just one printer, the PsrPrinter, in the package?

The standard Printer formats the code as we do it in all of Nette. Since Nette was created much earlier than PSR, and also because PSR for many years did not deliver standards in time, but sometimes even with several years of delay from the introduction of a new feature in PHP, this resulted in a few minor differences in the coding standard. The bigger difference is just the use of tabs instead of spaces. We know that by using tabs in our projects we allow for width adjustment, which is essential for people with visual impairments. An example of a minor difference is the placement of the curly brace on a separate line for functions and methods and always. We see the PSR recommendation as illogical and leading to a decrease in code clarity.

Types

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

use Nette\PhpGenerator\Type;

$member->setType('array'); // or Type::Array;
$member->setType('array|string'); // or Type::union('array', 'string')
$member->setType('Foo&Bar'); // or Type::intersection(Foo::class, Bar::class)
$member->setType(null); // removes type

The same applies to the method setReturnType().

Literals

With Literal you can pass arbitrary PHP code to, for example, default property or parameter values etc:

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

You can also pass parameters to Literal and have it formatted into valid PHP code using special placeholders:

new Literal('substr(?, ?)', [$a, $b]);
// generates, for example: substr('hello', 5);

Attributes

You can add PHP 8 attributes to all classes, methods, properties, constants, enum cases, functions, closures and parameters. Literals can also be used as parameter values.

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

Namespace

Classes, traits, interfaces and enums (hereinafter classes) can be grouped into namespaces (class 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 throws exception.

You can define use-statements:

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

To simplify a fully qualified class, function or constant name according to the defined aliases, use the simplifyName method:

echo $namespace->simplifyName('Foo\Bar'); // 'Bar', because 'Foo' is current namespace
echo $namespace->simplifyName('iter\range', $namespace::NameFunction); // 'range', because of the defined use-statement

Conversely, you can convert a simplified class, function or constant name to a fully qualified one using the resolveName method:

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

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 simplify to A
	->addTrait('Bar\AliasedClass'); // it will simplify to AliasedClass

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

echo $namespace;

// or use PsrPrinter for output conforming to 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, functions 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)

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

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

echo $file;

// or use PsrPrinter for output conforming to 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
{
}

function foo()
{
}

Generating According to Existing Ones

In addition to being able to model classes and functions using the API described above, you can also have them automatically generated using existing ones:

// creates a class identical to the PDO class
$class = Nette\PhpGenerator\ClassType::from(PDO::class);

// creates a function identical to trim()
$function = Nette\PhpGenerator\GlobalFunction::from('trim');

// creates a closure as specified
$closure = Nette\PhpGenerator\Closure::from(
	function (stdClass $a, $b = null) {},
);

Function and 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::from(Foo::class, withBodies: true);

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

Loading from PHP File

You can also load functions, classes, interfaces and enums directly from a string of PHP code. For example, we create ClassType object this way:

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

	class Demo
	{
		public $foo;
	}
	XX);

When loading classes from PHP code, single line comments outside of method bodies are ignored (e.g. for properties, etc.) because this library does not have an API to work with them.

You can also load the entire PHP file directly, which can contain any number of classes, functions or even multiple namespaces:

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

The initial file comment and the strict_types declaration are also loaded. On the other hand, all other global code is ignored.

This requires nikic/php-parser to be installed.

(If you need to manipulate global code in files or individual statements in method bodies, it is better to use the nikic/php-parser library directly.)

Variables Dumper

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

$dumper = new Nette\PhpGenerator\Dumper;

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

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

Compatibility Table

  • PhpGenerator 4.0 is compatible with PHP 8.0 to 8.2
  • PhpGenerator 3.6 is compatible with PHP 7.2 to 8.2
  • 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

More Repositories

1

utils

πŸ›  Lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.
PHP
1,868
star
2

tracy

😎 Tracy: the addictive tool to ease debugging PHP code for cool developers. Friendly design, logging, profiler, advanced features like debugging AJAX calls or CLI support. You will love it.
PHP
1,712
star
3

nette

πŸ‘ͺ METAPACKAGE for Nette Framework components
PHP
1,514
star
4

latte

β˜• Latte: the safest & truly intuitive templates for PHP. Engine for those who want the most secure PHP sites.
PHP
1,044
star
5

finder

πŸ” Finder: find files and directories with an intuitive API.
931
star
6

neon

🍸 Encodes and decodes NEON file format.
PHP
879
star
7

robot-loader

πŸ€ RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.
PHP
854
star
8

di

πŸ’Ž Flexible, compiled and full-featured Dependency Injection Container with perfectly usable autowiring and support for all new PHP 7 features.
PHP
841
star
9

schema

πŸ“ Validating data structures against a given Schema.
PHP
811
star
10

bootstrap

πŸ…± The simple way to configure and bootstrap your Nette application.
PHP
654
star
11

forms

πŸ“ Generating, validating and processing secure forms in PHP. Handy API, fully customizable, server & client side validation and mature design.
PHP
470
star
12

database

πŸ’Ύ A database layer with a familiar PDO-like API but much more powerful. Building queries, advanced joins, drivers for MySQL, PostgreSQL, SQLite, MS SQL Server and Oracle.
PHP
470
star
13

mail

A handy library for creating and sending emails in PHP
PHP
448
star
14

tester

Tester: enjoyable unit testing in PHP with code coverage reporter. 🍏🍏🍎🍏
PHP
440
star
15

http

🌐 Abstraction for HTTP request, response and session. Provides careful data sanitization and utility for URL and cookies manipulation.
PHP
437
star
16

caching

⏱ Caching library with easy-to-use API and many cache backends.
PHP
390
star
17

application

πŸ† A full-stack component-based MVC kernel for PHP that helps you write powerful and modern web applications. Write less, have cleaner code and your work will bring you joy.
PHP
384
star
18

security

πŸ”‘ Provides authentication, authorization and a role-based access control management via ACL (Access Control List)
PHP
338
star
19

component-model

βš› Component model foundation for Nette.
PHP
251
star
20

routing

Nette Routing: two-ways URL conversion
PHP
220
star
21

sandbox

142
star
22

tokenizer

[DISCONTINUED] Source code tokenizer
PHP
141
star
23

safe-stream

SafeStream: atomic and safe manipulation with files via native PHP functions.
PHP
117
star
24

docs

πŸ“– The Nette documentation
116
star
25

web-project

Standard Web Project: a simple skeleton application using the Nette
Latte
102
star
26

reflection

[DISCONTINUED] Docblock annotations parser and common reflection classes
PHP
94
star
27

examples

πŸŽ“ Examples demonstrating the Nette Framework.
88
star
28

code-checker

βœ… A simple tool to check source code against a set of Nette coding standards.
PHP
85
star
29

web-addons.nette.org

[DISCONTINUED] Website https://addons.nette.org source code.
PHP
55
star
30

coding-standard

Nette Coding Standard code checker & fixer
PHP
40
star
31

command-line

⌨ Command line options and arguments parser.
PHP
37
star
32

type-fixer

πŸ†™ A tool to automatically update typehints in your code.
PHP
29
star
33

resources

Client-side resources for Nette Framework.
23
star
34

latte-tools

Twig & HTML to Latte converters
PHP
22
star
35

grunt-nette-tester

Grunt plugin for Nette Tester
JavaScript
20
star
36

middleware

PHP
20
star
37

deprecated

[DISCONTINUED] APIs and features removed from Nette Framework
PHP
19
star
38

safe

πŸ›‘ PHP functions smarten up to throw exceptions instead of returning false or triggering errors.
PHP
17
star
39

nette-minified

[DISCONTINUED] Minified version of Nette Framework.
PHP
16
star
40

tutorial-todo

[DISCONTINUED] Tutorial for simple task manager.
PHP
10
star
41

union

[READ-ONLY] Subtree union of Nette repositories
PHP
7
star
42

assistant

PHP
3
star
43

.github

1
star