SlideShare a Scribd company logo
1 of 108
Download to read offline
Code Generation
in PHP
c9s
Yo-An Lin
@c9s
@c9s
@c9s_en
C9S	Hacker	News
PHPBrew, R3, Pux, ....
Someone	started	a	web	
framework.....
For	the	web,	of	course.
It	was	started	from	small
3	years	later,	it	looks	like	this
The Problems
Web Frameworks have too
many conditions for different
environment.
Including dynamic mechanism
& feature checking
Frameworks usually do this
• Integrate configuration file & default configuration.
• Decide which statements to be run in production /
development.
• Dynamically setter/getter dispatching in ORM
(keys can't be analyzed)
• Check which implementation is supported. (e.g.
extensions, PHP VM versions....)
• etc...
As the framework is getting bigger
and bigger, the more conditions will
need to be added into the application.
1. Detecting Environment
in Frameworks.
Detecting Environment
<?php
$environment = $_ENV['PHIFTY_ENV'];
if ($environment === "dev") {
// do something for development env
} else if ($environment === "testing") {
// do something for testing env
} else if ($environment === "production") {
// do something for production env
}
Detecting Environment
<?php
if ($environment === "dev") {
$event->bind("before_route", function() { /* ... */ });
$event->bind("finalize", function() { /* ... */ });
} else if ($environment === "production") {
$event->bind("before_route", function() { /* ... */ });
$event->bind("finalize", function() { /* ... */ });
}
Detecting Environment
<?php
if ($environment == "dev") {
require "environment/dev.php";
} else if ($environment == "production") {
require "environment/production.php";
}
Environment checking is
everywhere in frameworks.
for example
database connection
configuration
template engine configuration
(cache, recompile or not)
whether to cache database
queries or not..
etc....
2. Checking
Implementations
Checking Implementation
<?php
use SymfonyComponentYamlDumper;
function encode($data) {
if (extension_loaded('yaml')) {
return yaml_emit($data);
}
// fallback to pure PHP implementation
$dumper = new Dumper();
return $dumper->dump($array);
}
3. Integrating Config
Values
Integration Config Values
<?php
if (extension_loaded('mongo')) {
$container->mongo = function() use ($someConfigArray) {
if (isset($someConfigArray['mongo_host'])) {
return new MongoClient($someConfigArray['mongo_host']);
}
return new MongoClient('....');
};
}
4. Magic Setters/Getters
Magic Setters/Getters
<?php
class MyArray
{
protected $data = [];
public function __set($key, $value)
{
$this->data[ $key ] = $value;
}
public function __get($key)
{
return $this->data[ $key ];
}
}
CAN'T BE AUTO-
COMPLETED
IF WE'VE KNOWN THE
KEYS DEFINED IN SCHEMA
Magic Setters/Getters
PHP 5.6.10
declared properties are faster
declared functions/methods are faster
Magic Setters/Getters
<?php
class Foo
{
protected $name;
protected $price;
}
Doctrine can generates getter/setter methods for entities.
<?php
class Foo
{
protected $name;
protected $price;
public function getName()
{
return $this->name;
}
public function getPrice()
{
return $this->price;
}
}
Types of Code Generation
Types of Code Generation
• Low Level Code Generation: JIT (Just-in-time
compiler)
• High Level Code Generation: PHP to PHP,
reducing runtime costs.
1. Low Level Code
Generation
JIT (Just-in-time
compilation)
Why Types Are Important to
the Runtime System of VMs?
function add($a, $b) {
return $a + $b;
}
We	don't	know	the	types
function add($a, $b) {
return $a + $b;
}
ZEND_ADD
ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
{
USE_OPLINE
zend_free_op free_op1, free_op2;
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) {
if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
result = EX_VAR(opline->result.var);
fast_long_add_function(result, op1, op2);
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
} else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) {
if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
ZEND_VM_NEXT_OPCODE();
}
}
SAVE_OPLINE();
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) {
op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R);
}
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) {
op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R);
}
add_function(EX_VAR(opline->result.var), op1, op2);
FREE_OP1();
FREE_OP2();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
long	+	long	or	long	+	double
ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
{
USE_OPLINE
zend_free_op free_op1, free_op2;
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) {
if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
result = EX_VAR(opline->result.var);
fast_long_add_function(result, op1, op2);
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
} else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) {
if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
ZEND_VM_NEXT_OPCODE();
}
}
SAVE_OPLINE();
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) {
op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R);
}
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) {
op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R);
}
add_function(EX_VAR(opline->result.var), op1, op2);
FREE_OP1();
FREE_OP2();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
double	+	double	|	double	+	long
ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
{
USE_OPLINE
zend_free_op free_op1, free_op2;
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) {
if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
result = EX_VAR(opline->result.var);
fast_long_add_function(result, op1, op2);
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
} else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) {
if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
ZEND_VM_NEXT_OPCODE();
}
}
SAVE_OPLINE();
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) {
op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R);
}
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) {
op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R);
}
add_function(EX_VAR(opline->result.var), op1, op2);
FREE_OP1();
FREE_OP2();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
for	other	types
ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
zval op1_copy, op2_copy;
int converted = 0;
while (1) {
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG): {
zend_long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2);
/* check for overflow by comparing sign bits */
if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
} else {
ZVAL_LONG(result, lval);
}
return SUCCESS;
}
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
return SUCCESS;
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
if ((result == op1) && (result == op2)) {
/* $a += $a */
return SUCCESS;
}
if (result != op1) {
ZVAL_DUP(result, op1);
}
zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
return SUCCESS;
default:
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
long	+	long
ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
zval op1_copy, op2_copy;
int converted = 0;
while (1) {
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG): {
zend_long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2);
/* check for overflow by comparing sign bits */
if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
} else {
ZVAL_LONG(result, lval);
}
return SUCCESS;
}
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
return SUCCESS;
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
if ((result == op1) && (result == op2)) {
/* $a += $a */
return SUCCESS;
}
if (result != op1) {
ZVAL_DUP(result, op1);
}
zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
return SUCCESS;
default:
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
long	+	double	
double	+	long	
double	+	double
ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
zval op1_copy, op2_copy;
int converted = 0;
while (1) {
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG): {
zend_long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2);
/* check for overflow by comparing sign bits */
if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) {
ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
} else {
ZVAL_LONG(result, lval);
}
return SUCCESS;
}
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
return SUCCESS;
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
if ((result == op1) && (result == op2)) {
/* $a += $a */
return SUCCESS;
}
if (result != op1) {
ZVAL_DUP(result, op1);
}
zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
return SUCCESS;
default:
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
array	+	array
http://jpauli.github.io/2015/02/05/zend-vm-executor.html
More details: Getting into the Zend Execution engine (PHP 5)
function add($a, $b) {
return $a + $b;
}
We	don't	know	the	types
function add($a, $b) {
return $a + $b;
}
OK,	Launch	a	thread	for	watching	
the	types	of	function	arguments
function add($a, $b) {
return $a + $b;
}
This	is	so	called	Trace-Based	JIT	
Compilation.	(also	implemented	in	
V8)
function add($a, $b) {
return $a + $b;
}
add(1,2);
int int
function add($a, $b) {
return $a + $b;
}
add(1,2);
int int
add(1,2);
add(1,2);
..... x N as a threshold
function add($a, $b) {
return $a + $b;
}
int int
movl	(address	of	a),	%eax	
movl	(address	of	b),	%ebx	
addl	%ebx,	%eax
OK	Enough,	Let's	compile	a	function:	
_add_int_int(int	a,	int	b)
libjit
http://www.gnu.org/software/libjit/ LibJIT is a library that provides
generic Just-In-Time compiler
functionality independent of any
particular byte-code, language,
or runtime.
int mul_add(int x, int y, int z)
{
return x * y + z;
}
#include <jit/jit.h>
jit_context_t context;
...
context = jit_context_create();
jit_context_build_start(context);
jit_function_t function;
...
function = jit_function_create(context, signature);
jit_type_t params[3];
jit_type_t signature;
...
params[0] = jit_type_int;
params[1] = jit_type_int;
params[2] = jit_type_int;
signature = jit_type_create_signature
(jit_abi_cdecl, jit_type_int, params, 3, 1);
jit_value_t x, y, z;
...
x = jit_value_get_param(function, 0);
y = jit_value_get_param(function, 1);
z = jit_value_get_param(function, 2);
jit_value_t temp1, temp2;
...
temp1 = jit_insn_mul(function, x, y);
temp2 = jit_insn_add(function, temp1, z);
jit_insn_return(function, temp2);
jit_function_compile(function);
jit_context_build_end(context);
jitfu php extension
https://github.com/krakjoe/jitfu Creating native instructions in
PHP since 2014.
JIT-Fu is a PHP extension that
exposes an OO API for the
creation of native instructions to
PHP userland, using libjit.
Joe Watkins
@krakjoe
<?php
use JITFUContext;
use JITFUType;
use JITFUSignature;
use JITFUFunc;
use JITFUValue;
$context = new Context();
$integer = Type::of(Type::int);
$function = new Func($context, new Signature($integer, $integer,
$integer), function($args) use($integer) {
$this->doReturn(
$this->doAdd($this->doMul($args[0], $args[1), $args[2])
);
});
Pretty much simpler,
isn't it?
You can get it through
phpbrew
phpbrew	ext	install	github:krakjoe/jitfu		
						--	--with-libjit=/opt/local
Related Projects
PHPPHP
https://github.com/ircmaxell/PHPPHP A PHP VM implementation
written in PHP. This is a basic
VM implemented in PHP using
the AST generating parser
developed by @nikic
Anthony Ferrara
@ircmaxell
recki-ct
https://github.com/google/recki-ct Recki-CT is a set of tools that
implement a compiler for PHP,
and is written in PHP!
Specifically, Recki-CT compiles
a subset of PHP code. The
subset is designed to allow a
code base to be statically
analyzed.
Anthony Ferrara
@ircmaxell
LLVM vs LIBJIT?
http://eli.thegreenplace.net/2014/01/15/some-thoughts-on-llvm-vs-libjit
2. High Level Code
Generation
Compile PHP to PHP
Compile PHP to Faster
PHP
CodeGen
github.com/c9s/CodeGen CodeGen transforms your
dynamic calls to static code
Framework Bootstrap
Script
Phifty Framework
Bootstrap Script
https://github.com/c9s/Phifty/blob/master/src/Phifty/Bootstrap.php
<?php
use ConfigKitConfigCompiler;
use ConfigKitConfigLoader;
// get PH_ROOT from phifty-core
defined( 'PH_ROOT' ) || define( 'PH_ROOT', getcwd() );
defined( 'PH_APP_ROOT' ) || define( 'PH_APP_ROOT' , getcwd() );
defined( 'DS' ) || define( 'DS' , DIRECTORY_SEPARATOR );
function initConfigLoader()
{
// We load other services from the definitions in config file
// Simple load three config files (framework.yml, database.yml, application.yml)
$loader = new ConfigLoader;
if ( file_exists( PH_APP_ROOT . '/config/framework.yml') ) {
$loader->load('framework', PH_APP_ROOT . '/config/framework.yml');
}
// This is for DatabaseService
if ( file_exists( PH_APP_ROOT . '/db/config/database.yml') ) {
$loader->load('database', PH_APP_ROOT . '/db/config/database.yml');
} elseif ( file_exists( PH_APP_ROOT . '/config/database.yml') ) {
$loader->load('database', PH_APP_ROOT . '/config/database.yml');
}
// Config for application, services does not depends on this config file.
if ( file_exists( PH_APP_ROOT . '/config/application.yml') ) {
$loader->load('application', PH_APP_ROOT . '/config/application.yml');
}
// Only load testing configuration when environment
// is 'testing'
if ( getenv('PHIFTY_ENV') === 'testing' ) {
if ( file_exists( PH_APP_ROOT . '/config/testing.yml' ) ) {
$loader->load('testing', ConfigCompiler::compile(PH_APP_ROOT . '/config/testing.yml') );
}
}
return $loader;
}
A lot of dynamic checking
<?php
$kernel = new PhiftyKernel;
$kernel->prepare(); // prepare constants
$composerLoader = require PH_ROOT . '/vendor/autoload.php';
$kernel->registerService( new PhiftyServiceClassLoaderService(getSplClassLoader()));
$configLoader = initConfigLoader();
$kernel->registerService( new PhiftyServiceConfigService($configLoader));
$kernel->registerService( new PhiftyServiceEventService );
// if the framework config is defined.
if ( $configLoader->isLoaded('framework') ) {
// we should load database service before other services
// because other services might need database service
if ( $configLoader->isLoaded('database') ) {
$kernel->registerService( new PhiftyServiceDatabaseService );
}
if ( $appconfigs = $kernel->config->get('framework','Applications') ) {
foreach ($appconfigs as $appname => $appconfig) {
$kernel->classloader->addNamespace( array(
$appname => array( PH_APP_ROOT . '/applications' , PH_ROOT . '/applications' )
));
}
}
if ( $services = $kernel->config->get('framework','Services') ) {
foreach ($services as $name => $options) {
// not full qualified classname
$class = ( false === strpos($name,'') ) ? ('PhiftyService' . $name) : $name;
$kernel->registerService( new $class , $options );
}
}
}
$kernel->init();
Dynamic initialization
~1000 lines to bootstrap
Laravel Framework
Bootstrapping
https://github.com/laravel/framework/blob/5.1/src/Illuminate/Foundation/Application.php
public function __construct($basePath = null)
{
$this->registerBaseBindings();
$this->registerBaseServiceProviders();
$this->registerCoreContainerAliases();
if ($basePath) {
$this->setBasePath($basePath);
}
}
/**
* Register the core class aliases in the container.
*
* @return void
*/
public function registerCoreContainerAliases()
{
$aliases = [
'app' => ['IlluminateFoundationApplication', 'IlluminateContracts
ContainerContainer', 'IlluminateContractsFoundationApplication'],
'auth' => 'IlluminateAuthAuthManager',
'auth.driver' => ['IlluminateAuthGuard', 'IlluminateContractsAuthGuard'],
'auth.password.tokens' => 'IlluminateAuthPasswordsTokenRepositoryInterface',
'url' => ['IlluminateRoutingUrlGenerator', 'IlluminateContractsRouting
UrlGenerator'],
.....
20 lines cut
.....
'validator' => ['IlluminateValidationFactory', 'IlluminateContracts
ValidationFactory'],
'view' => ['IlluminateViewFactory', 'IlluminateContractsViewFactory'],
];
foreach ($aliases as $key => $aliases) {
foreach ((array) $aliases as $alias) {
$this->alias($key, $alias);
}
}
}
public function detectEnvironment(Closure $callback)
{
$args = isset($_SERVER['argv']) ? $_SERVER['argv'] : null;
return $this['env'] = (new EnvironmentDetector())->detect($callback, $args);
}
IlluminateFoundationBootstrapConfigureLogging ~120 lines
IlluminateFoundationBootstrapDetectEnvironment ~ 29 lines
IlluminateFoundationBootstrapHandleExceptions
IlluminateFoundationBootstrapLoadConfiguration
IlluminateFoundationBootstrapRegisterFacades
IlluminateFoundationBootstrapRegisterProviders
~3000 lines of code to
bootstrap an application
Using CodeGen to reduce
checks and remove conditions
Declaring Block
use CodeGenBlock;
use CodeGenComment;
use CodeGenCommentBlock; $block = new Block;
$block[] = '<?php';
$block[] = new CommentBlock([
"This file is auto-generated through 'bin/phifty bootstrap' command.",
"Don't modify this file directly",
"",
"For more information, please visit https://github.com/c9s/Phifty",
]);
Declaring Require Statement
// Generates: $kernel->registerService(new PhiftyServiceProvider
EventServiceProvider());
$block[] = new Comment('The event service is required for every component.');
$block[] = new RequireClassStatement('PhiftyServiceProviderEventServiceProvider');
$block[] = new Statement(new MethodCall('$kernel', 'registerService', [
new NewObject('PhiftyServiceProviderEventServiceProvider'),
]));
Declaring Conditional
Statement
$stmt = new ConditionalStatement($foo == 1, '$foo = 1');
$stmt->when($foo == 2, function() {
return '$foo = 2;';
});
$stmt->when($foo == 3, function() {
return '$foo = 3;';
});
require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/ActionServiceProvider.php';
$kernel->registerService(new PhiftyServiceProviderActionServiceProvider(array (
'DefaultFieldView' => 'ActionKitFieldViewBootstrapFieldView',
)));
require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/PuxRouterServiceProvider.php';
$kernel->registerService(new PhiftyServiceProviderPuxRouterServiceProvider(array ()));
require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/LibraryServiceProvider.php';
$kernel->registerService(new PhiftyServiceProviderLibraryServiceProvider(array ()));
require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/ViewServiceProvider.php';
$kernel->registerService(new PhiftyServiceProviderViewServiceProvider(array (
'Backend' => 'twig',
'Class' => 'AppViewPageView',
)));
require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/MailerServiceProvider.php';
$kernel->registerService(new PhiftyServiceProviderMailerServiceProvider(array (
'Transport' => 'MailTransport',
)));
require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/MongodbServiceProvider.php';
$kernel->registerService(new PhiftyServiceProviderMongodbServiceProvider(array ( 'DSN' => 'mongodb://
localhost',)));
require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/CacheServiceProvider.php';
$kernel->registerService(new PhiftyServiceProviderCacheServiceProvider(array ()));
require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/LocaleServiceProvider.php';
$kernel->registerService(new PhiftyServiceProviderLocaleServiceProvider(array (
'Directory' => 'locale',
'Default' => 'zh_TW',
'Domain' => '___',
'Langs' =>
array (
0 => 'en',
1 => 'zh_TW',
),
)));
Integrating PHP Parser for
CodeGen with Annotation
nikic/PHP-Parser
PHP-Parser
https://github.com/nikic/PHP-Parser a PHP 5.2 to PHP 5.6 parser written
in PHP. Its purpose is to simplify
static code analysis and
manipulation.
// @codegen
if ($environment == "development") {
$handler = new DevelopmentHandler;
} else {
$handler = new ProductionHandler;
}
$handler = new DevelopmentHandler;
LazyRecord
https://github.com/c9s/LazyRecord ORM implemented with Code
Generation Technologies
<?php
namespace LazyRecordSchemaFactory;
use ClassTemplateTemplateClassFile;
use ClassTemplateClassFile;
use LazyRecordSchemaSchemaInterface;
use LazyRecordSchemaDeclareSchema;
use DoctrineCommonInflectorInflector;
class BaseModelClassFactory
{
public static function create(DeclareSchema $schema, $baseClass) {
$cTemplate = new ClassFile($schema->getBaseModelClass());
$cTemplate->addConsts(array(
'schema_proxy_class' => $schema->getSchemaProxyClass(),
'collection_class' => $schema->getCollectionClass(),
'model_class' => $schema->getModelClass(),
'table' => $schema->getTable(),
'read_source_id' => $schema->getReadSourceId(),
'write_source_id' => $schema->getWriteSourceId(),
'primary_key' => $schema->primaryKey,
));
$cTemplate->addMethod('public', 'getSchema', [], [
'if ($this->_schema) {',
' return $this->_schema;',
'}',
'return $this->_schema = LazyRecordSchemaSchemaLoader::load(' . var_export($schema-
>getSchemaProxyClass(),true) . ');',
]);
$cTemplate->addStaticVar('column_names', $schema->getColumnNames());
$cTemplate->addStaticVar('column_hash', array_fill_keys($schema->getColumnNames(), 1 ) );
$cTemplate->addStaticVar('mixin_classes', array_reverse($schema-
<?php
namespace UserBundleModel;
use LazyRecordBaseModel;
class UserBase
extends BaseModel
{
const schema_proxy_class = 'UserBundleModelUserSchemaProxy';
const collection_class = 'UserBundleModelUserCollection';
const model_class = 'UserBundleModelUser';
const table = 'users';
const read_source_id = 'default';
const write_source_id = 'default';
const primary_key = 'id';
public static $column_names = array (
0 => 'id',
1 => 'password',
2 => 'auth_token',
3 => 'account',
4 => 'confirmed',
5 => 'email',
6 => 'name',
7 => 'cellphone',
8 => 'phone',
9 => 'role',
10 => 'company',
11 => 'receive_email',
12 => 'receive_sms',
13 => 'remark',
14 => 'org_id',
);
public static $column_hash = array (
'id' => 1,
'password' => 1,
'auth_token' => 1,
'account' => 1,
'confirmed' => 1,
'email' => 1,
ActionKit
github.com/c9s/ActionKit ActionKit handles your PHP web application
logics and record relationships
Generating CRUD Handler
automatically in the Runtime
AppModelProduct
AppActionCreateProduct	
AppActionUpdateProduct	
AppActionDeleteProduct
ActionKit Generates API classes automatically
use AppActionCreateProduct;
$create = new CreateProduct(['name' => 'Product I', 'sn' =>
'PN-12345677']);
$success = $create->invoke();
The SPL autoloader generates the action class in cache
directory automatically.
Trigger	ActionKit	ActionGenerator	by	
	SPL	autoloader
<?php
/**
This is an auto-generated file,
Please DO NOT modify this file directly.
*/
namespace AppAction;
use ActionKitAction;
use ActionKitRecordActionBaseRecordAction;
use ActionKitRecordActionUpdateRecordAction;
class UpdateStore extends UpdateRecordAction {
public $recordClass = 'AppModelProduct';
}
ConfigKit
https://github.com/c9s/ConfigKit The optimized config loader
use ConfigKitConfigLoader;
$loader = new ConfigLoader();
if (file_exists($baseDir.'/config/framework.yml')) {
$loader->load('framework', $baseDir.'/config/framework.yml');
}
// This is for DatabaseService
if (file_exists($baseDir.'/db/config/database.yml')) {
$loader->load('database', $baseDir.'/db/config/database.yml');
} elseif (file_exists($baseDir.'/config/database.yml')) {
$loader->load('database', $baseDir.'/config/database.yml');
}
use CodeGenGeneratorAppClassGenerator;
use ConfigKitConfigLoader;
$configLoader = new ConfigLoader;
$configClassGenerator = new AppClassGenerator([
'namespace' => 'App',
'prefix' => 'App'
]);
$configClass = $configClassGenerator->generate($configLoader);
$classPath = $configClass->generatePsr4ClassUnder('app');
$block[] = new RequireStatement(PH_APP_ROOT . DIRECTORY_SEPARATOR .
$classPath);
Thank You

More Related Content

What's hot

Introdução ao Perl 6
Introdução ao Perl 6Introdução ao Perl 6
Introdução ao Perl 6garux
 
Perl.Hacks.On.Vim
Perl.Hacks.On.VimPerl.Hacks.On.Vim
Perl.Hacks.On.VimLin Yo-An
 
Create your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaCreate your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaPatrick Allaert
 
Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In PerlKang-min Liu
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?Nikita Popov
 
Swift Programming Language
Swift Programming LanguageSwift Programming Language
Swift Programming LanguageGiuseppe Arici
 
Static Optimization of PHP bytecode (PHPSC 2017)
Static Optimization of PHP bytecode (PHPSC 2017)Static Optimization of PHP bytecode (PHPSC 2017)
Static Optimization of PHP bytecode (PHPSC 2017)Nikita Popov
 
PHP in 2018 - Q4 - AFUP Limoges
PHP in 2018 - Q4 - AFUP LimogesPHP in 2018 - Q4 - AFUP Limoges
PHP in 2018 - Q4 - AFUP Limoges✅ William Pinaud
 
Functional Structures in PHP
Functional Structures in PHPFunctional Structures in PHP
Functional Structures in PHPMarcello Duarte
 
Wx::Perl::Smart
Wx::Perl::SmartWx::Perl::Smart
Wx::Perl::Smartlichtkind
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Jeff Carouth
 
Being functional in PHP (DPC 2016)
Being functional in PHP (DPC 2016)Being functional in PHP (DPC 2016)
Being functional in PHP (DPC 2016)David de Boer
 
PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021Ayesh Karunaratne
 
Just-In-Time Compiler in PHP 8
Just-In-Time Compiler in PHP 8Just-In-Time Compiler in PHP 8
Just-In-Time Compiler in PHP 8Nikita Popov
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type Systemabrummett
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to SwiftGiordano Scalzo
 
Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)brian d foy
 

What's hot (20)

Introdução ao Perl 6
Introdução ao Perl 6Introdução ao Perl 6
Introdução ao Perl 6
 
Perl.Hacks.On.Vim
Perl.Hacks.On.VimPerl.Hacks.On.Vim
Perl.Hacks.On.Vim
 
Php string function
Php string function Php string function
Php string function
 
Create your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaCreate your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 Verona
 
Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In Perl
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?
 
Swift Programming Language
Swift Programming LanguageSwift Programming Language
Swift Programming Language
 
Static Optimization of PHP bytecode (PHPSC 2017)
Static Optimization of PHP bytecode (PHPSC 2017)Static Optimization of PHP bytecode (PHPSC 2017)
Static Optimization of PHP bytecode (PHPSC 2017)
 
PHP in 2018 - Q4 - AFUP Limoges
PHP in 2018 - Q4 - AFUP LimogesPHP in 2018 - Q4 - AFUP Limoges
PHP in 2018 - Q4 - AFUP Limoges
 
Functional Structures in PHP
Functional Structures in PHPFunctional Structures in PHP
Functional Structures in PHP
 
Wx::Perl::Smart
Wx::Perl::SmartWx::Perl::Smart
Wx::Perl::Smart
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Being functional in PHP (DPC 2016)
Being functional in PHP (DPC 2016)Being functional in PHP (DPC 2016)
Being functional in PHP (DPC 2016)
 
PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021
 
Just-In-Time Compiler in PHP 8
Just-In-Time Compiler in PHP 8Just-In-Time Compiler in PHP 8
Just-In-Time Compiler in PHP 8
 
Perl6 grammars
Perl6 grammarsPerl6 grammars
Perl6 grammars
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type System
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
 
Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)
 
Functions in PHP
Functions in PHPFunctions in PHP
Functions in PHP
 

Similar to Code Generation in PHP - PHPConf 2015

The mighty js_function
The mighty js_functionThe mighty js_function
The mighty js_functiontimotheeg
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Jason Lotito
 
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6FrontDays
 
Quick tour of PHP from inside
Quick tour of PHP from insideQuick tour of PHP from inside
Quick tour of PHP from insidejulien pauli
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest UpdatesIftekhar Eather
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesAnkit Rastogi
 
Php Reusing Code And Writing Functions
Php Reusing Code And Writing FunctionsPhp Reusing Code And Writing Functions
Php Reusing Code And Writing Functionsmussawir20
 
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxjava compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxpriestmanmable
 
Всеволод Струкчинский: Node.js
Всеволод Струкчинский: Node.jsВсеволод Струкчинский: Node.js
Всеволод Струкчинский: Node.jsYandex
 
PHP Internals and Virtual Machine
PHP Internals and Virtual MachinePHP Internals and Virtual Machine
PHP Internals and Virtual Machinejulien pauli
 
Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014Eric Hogue
 
Exercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera CymbronExercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera Cymbroncymbron
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & ToolsIan Barber
 
Mdp plus 2.1
Mdp plus 2.1Mdp plus 2.1
Mdp plus 2.1boedax
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionIan Barber
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016Manoj Kumar
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Seri Moth
 

Similar to Code Generation in PHP - PHPConf 2015 (20)

The mighty js_function
The mighty js_functionThe mighty js_function
The mighty js_function
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13
 
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
 
Quick tour of PHP from inside
Quick tour of PHP from insideQuick tour of PHP from inside
Quick tour of PHP from inside
 
PHP7 Presentation
PHP7 PresentationPHP7 Presentation
PHP7 Presentation
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
 
Php Reusing Code And Writing Functions
Php Reusing Code And Writing FunctionsPhp Reusing Code And Writing Functions
Php Reusing Code And Writing Functions
 
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxjava compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
 
Всеволод Струкчинский: Node.js
Всеволод Струкчинский: Node.jsВсеволод Струкчинский: Node.js
Всеволод Струкчинский: Node.js
 
PHP Internals and Virtual Machine
PHP Internals and Virtual MachinePHP Internals and Virtual Machine
PHP Internals and Virtual Machine
 
Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014
 
Exercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera CymbronExercícios Netbeans - Vera Cymbron
Exercícios Netbeans - Vera Cymbron
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & Tools
 
Mdp plus 2.1
Mdp plus 2.1Mdp plus 2.1
Mdp plus 2.1
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 Version
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Say It With Javascript
Say It With JavascriptSay It With Javascript
Say It With Javascript
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02
 

More from Lin Yo-An

Getting merged
Getting mergedGetting merged
Getting mergedLin Yo-An
 
OSDC.TW 2014 building popular open source projects
OSDC.TW 2014   building popular open source projectsOSDC.TW 2014   building popular open source projects
OSDC.TW 2014 building popular open source projectsLin Yo-An
 
Happy Go Programming
Happy Go ProgrammingHappy Go Programming
Happy Go ProgrammingLin Yo-An
 
Happy Go Programming Part 1
Happy Go Programming Part 1Happy Go Programming Part 1
Happy Go Programming Part 1Lin Yo-An
 
Secret sauce of building php applications
Secret sauce of building php applicationsSecret sauce of building php applications
Secret sauce of building php applicationsLin Yo-An
 
LazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHPLazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHPLin Yo-An
 
Vim Script Programming
Vim Script ProgrammingVim Script Programming
Vim Script ProgrammingLin Yo-An
 
CPAN 模組二三事
CPAN 模組二三事CPAN 模組二三事
CPAN 模組二三事Lin Yo-An
 
Vim Hacks (OSSF)
Vim Hacks (OSSF)Vim Hacks (OSSF)
Vim Hacks (OSSF)Lin Yo-An
 
Perl.Hacks.On.Vim Perlchina
Perl.Hacks.On.Vim PerlchinaPerl.Hacks.On.Vim Perlchina
Perl.Hacks.On.Vim PerlchinaLin Yo-An
 

More from Lin Yo-An (11)

Getting merged
Getting mergedGetting merged
Getting merged
 
OSDC.TW 2014 building popular open source projects
OSDC.TW 2014   building popular open source projectsOSDC.TW 2014   building popular open source projects
OSDC.TW 2014 building popular open source projects
 
Happy Go Programming
Happy Go ProgrammingHappy Go Programming
Happy Go Programming
 
Happy Go Programming Part 1
Happy Go Programming Part 1Happy Go Programming Part 1
Happy Go Programming Part 1
 
Secret sauce of building php applications
Secret sauce of building php applicationsSecret sauce of building php applications
Secret sauce of building php applications
 
LazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHPLazyRecord: The Fast ORM for PHP
LazyRecord: The Fast ORM for PHP
 
Vim Script Programming
Vim Script ProgrammingVim Script Programming
Vim Script Programming
 
CPAN 模組二三事
CPAN 模組二三事CPAN 模組二三事
CPAN 模組二三事
 
Vim Hacks (OSSF)
Vim Hacks (OSSF)Vim Hacks (OSSF)
Vim Hacks (OSSF)
 
Perl.Hacks.On.Vim Perlchina
Perl.Hacks.On.Vim PerlchinaPerl.Hacks.On.Vim Perlchina
Perl.Hacks.On.Vim Perlchina
 
Vim Hacks
Vim HacksVim Hacks
Vim Hacks
 

Recently uploaded

Transport layer issues and challenges - Guide
Transport layer issues and challenges - GuideTransport layer issues and challenges - Guide
Transport layer issues and challenges - GuideGOPINATHS437943
 
Vishratwadi & Ghorpadi Bridge Tender documents
Vishratwadi & Ghorpadi Bridge Tender documentsVishratwadi & Ghorpadi Bridge Tender documents
Vishratwadi & Ghorpadi Bridge Tender documentsSachinPawar510423
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleAlluxio, Inc.
 
Application of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptxApplication of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptx959SahilShah
 
welding defects observed during the welding
welding defects observed during the weldingwelding defects observed during the welding
welding defects observed during the weldingMuhammadUzairLiaqat
 
Piping Basic stress analysis by engineering
Piping Basic stress analysis by engineeringPiping Basic stress analysis by engineering
Piping Basic stress analysis by engineeringJuanCarlosMorales19600
 
Call Girls Narol 7397865700 Independent Call Girls
Call Girls Narol 7397865700 Independent Call GirlsCall Girls Narol 7397865700 Independent Call Girls
Call Girls Narol 7397865700 Independent Call Girlsssuser7cb4ff
 
CCS355 Neural Network & Deep Learning UNIT III notes and Question bank .pdf
CCS355 Neural Network & Deep Learning UNIT III notes and Question bank .pdfCCS355 Neural Network & Deep Learning UNIT III notes and Question bank .pdf
CCS355 Neural Network & Deep Learning UNIT III notes and Question bank .pdfAsst.prof M.Gokilavani
 
Arduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.pptArduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.pptSAURABHKUMAR892774
 
Risk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdfRisk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdfROCENODodongVILLACER
 
lifi-technology with integration of IOT.pptx
lifi-technology with integration of IOT.pptxlifi-technology with integration of IOT.pptx
lifi-technology with integration of IOT.pptxsomshekarkn64
 
IVE Industry Focused Event - Defence Sector 2024
IVE Industry Focused Event - Defence Sector 2024IVE Industry Focused Event - Defence Sector 2024
IVE Industry Focused Event - Defence Sector 2024Mark Billinghurst
 
Class 1 | NFPA 72 | Overview Fire Alarm System
Class 1 | NFPA 72 | Overview Fire Alarm SystemClass 1 | NFPA 72 | Overview Fire Alarm System
Class 1 | NFPA 72 | Overview Fire Alarm Systemirfanmechengr
 
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort serviceGurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort servicejennyeacort
 
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfgUnit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfgsaravananr517913
 
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)Dr SOUNDIRARAJ N
 
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsyncWhy does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsyncssuser2ae721
 

Recently uploaded (20)

Transport layer issues and challenges - Guide
Transport layer issues and challenges - GuideTransport layer issues and challenges - Guide
Transport layer issues and challenges - Guide
 
Vishratwadi & Ghorpadi Bridge Tender documents
Vishratwadi & Ghorpadi Bridge Tender documentsVishratwadi & Ghorpadi Bridge Tender documents
Vishratwadi & Ghorpadi Bridge Tender documents
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at Scale
 
Application of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptxApplication of Residue Theorem to evaluate real integrations.pptx
Application of Residue Theorem to evaluate real integrations.pptx
 
welding defects observed during the welding
welding defects observed during the weldingwelding defects observed during the welding
welding defects observed during the welding
 
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
🔝9953056974🔝!!-YOUNG call girls in Rajendra Nagar Escort rvice Shot 2000 nigh...
 
Piping Basic stress analysis by engineering
Piping Basic stress analysis by engineeringPiping Basic stress analysis by engineering
Piping Basic stress analysis by engineering
 
Call Girls Narol 7397865700 Independent Call Girls
Call Girls Narol 7397865700 Independent Call GirlsCall Girls Narol 7397865700 Independent Call Girls
Call Girls Narol 7397865700 Independent Call Girls
 
CCS355 Neural Network & Deep Learning UNIT III notes and Question bank .pdf
CCS355 Neural Network & Deep Learning UNIT III notes and Question bank .pdfCCS355 Neural Network & Deep Learning UNIT III notes and Question bank .pdf
CCS355 Neural Network & Deep Learning UNIT III notes and Question bank .pdf
 
Arduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.pptArduino_CSE ece ppt for working and principal of arduino.ppt
Arduino_CSE ece ppt for working and principal of arduino.ppt
 
Risk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdfRisk Assessment For Installation of Drainage Pipes.pdf
Risk Assessment For Installation of Drainage Pipes.pdf
 
lifi-technology with integration of IOT.pptx
lifi-technology with integration of IOT.pptxlifi-technology with integration of IOT.pptx
lifi-technology with integration of IOT.pptx
 
IVE Industry Focused Event - Defence Sector 2024
IVE Industry Focused Event - Defence Sector 2024IVE Industry Focused Event - Defence Sector 2024
IVE Industry Focused Event - Defence Sector 2024
 
Class 1 | NFPA 72 | Overview Fire Alarm System
Class 1 | NFPA 72 | Overview Fire Alarm SystemClass 1 | NFPA 72 | Overview Fire Alarm System
Class 1 | NFPA 72 | Overview Fire Alarm System
 
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort serviceGurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
Gurgaon ✡️9711147426✨Call In girls Gurgaon Sector 51 escort service
 
POWER SYSTEMS-1 Complete notes examples
POWER SYSTEMS-1 Complete notes  examplesPOWER SYSTEMS-1 Complete notes  examples
POWER SYSTEMS-1 Complete notes examples
 
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfgUnit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
 
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
 
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsyncWhy does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
Why does (not) Kafka need fsync: Eliminating tail latency spikes caused by fsync
 
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
 

Code Generation in PHP - PHPConf 2015

  • 3.
  • 7.
  • 10. Web Frameworks have too many conditions for different environment.
  • 11. Including dynamic mechanism & feature checking
  • 12. Frameworks usually do this • Integrate configuration file & default configuration. • Decide which statements to be run in production / development. • Dynamically setter/getter dispatching in ORM (keys can't be analyzed) • Check which implementation is supported. (e.g. extensions, PHP VM versions....) • etc...
  • 13. As the framework is getting bigger and bigger, the more conditions will need to be added into the application.
  • 15. Detecting Environment <?php $environment = $_ENV['PHIFTY_ENV']; if ($environment === "dev") { // do something for development env } else if ($environment === "testing") { // do something for testing env } else if ($environment === "production") { // do something for production env }
  • 16. Detecting Environment <?php if ($environment === "dev") { $event->bind("before_route", function() { /* ... */ }); $event->bind("finalize", function() { /* ... */ }); } else if ($environment === "production") { $event->bind("before_route", function() { /* ... */ }); $event->bind("finalize", function() { /* ... */ }); }
  • 17. Detecting Environment <?php if ($environment == "dev") { require "environment/dev.php"; } else if ($environment == "production") { require "environment/production.php"; }
  • 22. whether to cache database queries or not..
  • 25. Checking Implementation <?php use SymfonyComponentYamlDumper; function encode($data) { if (extension_loaded('yaml')) { return yaml_emit($data); } // fallback to pure PHP implementation $dumper = new Dumper(); return $dumper->dump($array); }
  • 27. Integration Config Values <?php if (extension_loaded('mongo')) { $container->mongo = function() use ($someConfigArray) { if (isset($someConfigArray['mongo_host'])) { return new MongoClient($someConfigArray['mongo_host']); } return new MongoClient('....'); }; }
  • 29. Magic Setters/Getters <?php class MyArray { protected $data = []; public function __set($key, $value) { $this->data[ $key ] = $value; } public function __get($key) { return $this->data[ $key ]; } } CAN'T BE AUTO- COMPLETED IF WE'VE KNOWN THE KEYS DEFINED IN SCHEMA
  • 30. Magic Setters/Getters PHP 5.6.10 declared properties are faster declared functions/methods are faster
  • 31. Magic Setters/Getters <?php class Foo { protected $name; protected $price; } Doctrine can generates getter/setter methods for entities. <?php class Foo { protected $name; protected $price; public function getName() { return $this->name; } public function getPrice() { return $this->price; } }
  • 32. Types of Code Generation
  • 33. Types of Code Generation • Low Level Code Generation: JIT (Just-in-time compiler) • High Level Code Generation: PHP to PHP, reducing runtime costs.
  • 34. 1. Low Level Code Generation
  • 36.
  • 37.
  • 38. Why Types Are Important to the Runtime System of VMs?
  • 39. function add($a, $b) { return $a + $b; } We don't know the types
  • 40. function add($a, $b) { return $a + $b; } ZEND_ADD ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
  • 41. ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; zval *op1, *op2, *result; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); fast_long_add_function(result, op1, op2); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); ZEND_VM_NEXT_OPCODE(); } } SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); } if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); } add_function(EX_VAR(opline->result.var), op1, op2); FREE_OP1(); FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } long + long or long + double
  • 42. ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; zval *op1, *op2, *result; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); fast_long_add_function(result, op1, op2); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); ZEND_VM_NEXT_OPCODE(); } } SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); } if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); } add_function(EX_VAR(opline->result.var), op1, op2); FREE_OP1(); FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } double + double | double + long
  • 43. ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; zval *op1, *op2, *result; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); fast_long_add_function(result, op1, op2); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); ZEND_VM_NEXT_OPCODE(); } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { result = EX_VAR(opline->result.var); ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); ZEND_VM_NEXT_OPCODE(); } } SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) { op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R); } if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) { op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R); } add_function(EX_VAR(opline->result.var), op1, op2); FREE_OP1(); FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } for other types
  • 44. ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */ { zval op1_copy, op2_copy; int converted = 0; while (1) { switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { case TYPE_PAIR(IS_LONG, IS_LONG): { zend_long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2); /* check for overflow by comparing sign bits */ if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK) && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) { ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2)); } else { ZVAL_LONG(result, lval); } return SUCCESS; } case TYPE_PAIR(IS_LONG, IS_DOUBLE): ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); return SUCCESS; case TYPE_PAIR(IS_DOUBLE, IS_LONG): ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); return SUCCESS; case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE): ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); return SUCCESS; case TYPE_PAIR(IS_ARRAY, IS_ARRAY): if ((result == op1) && (result == op2)) { /* $a += $a */ return SUCCESS; } if (result != op1) { ZVAL_DUP(result, op1); } zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0); return SUCCESS; default: if (Z_ISREF_P(op1)) { op1 = Z_REFVAL_P(op1); long + long
  • 45. ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */ { zval op1_copy, op2_copy; int converted = 0; while (1) { switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { case TYPE_PAIR(IS_LONG, IS_LONG): { zend_long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2); /* check for overflow by comparing sign bits */ if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK) && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) { ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2)); } else { ZVAL_LONG(result, lval); } return SUCCESS; } case TYPE_PAIR(IS_LONG, IS_DOUBLE): ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); return SUCCESS; case TYPE_PAIR(IS_DOUBLE, IS_LONG): ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); return SUCCESS; case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE): ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); return SUCCESS; case TYPE_PAIR(IS_ARRAY, IS_ARRAY): if ((result == op1) && (result == op2)) { /* $a += $a */ return SUCCESS; } if (result != op1) { ZVAL_DUP(result, op1); } zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0); return SUCCESS; default: if (Z_ISREF_P(op1)) { op1 = Z_REFVAL_P(op1); long + double double + long double + double
  • 46. ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */ { zval op1_copy, op2_copy; int converted = 0; while (1) { switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { case TYPE_PAIR(IS_LONG, IS_LONG): { zend_long lval = Z_LVAL_P(op1) + Z_LVAL_P(op2); /* check for overflow by comparing sign bits */ if ((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK) && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK)) { ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2)); } else { ZVAL_LONG(result, lval); } return SUCCESS; } case TYPE_PAIR(IS_LONG, IS_DOUBLE): ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2)); return SUCCESS; case TYPE_PAIR(IS_DOUBLE, IS_LONG): ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2))); return SUCCESS; case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE): ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2)); return SUCCESS; case TYPE_PAIR(IS_ARRAY, IS_ARRAY): if ((result == op1) && (result == op2)) { /* $a += $a */ return SUCCESS; } if (result != op1) { ZVAL_DUP(result, op1); } zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0); return SUCCESS; default: if (Z_ISREF_P(op1)) { op1 = Z_REFVAL_P(op1); array + array
  • 48. function add($a, $b) { return $a + $b; } We don't know the types
  • 49. function add($a, $b) { return $a + $b; } OK, Launch a thread for watching the types of function arguments
  • 50. function add($a, $b) { return $a + $b; } This is so called Trace-Based JIT Compilation. (also implemented in V8)
  • 51. function add($a, $b) { return $a + $b; } add(1,2); int int
  • 52. function add($a, $b) { return $a + $b; } add(1,2); int int add(1,2); add(1,2); ..... x N as a threshold
  • 53. function add($a, $b) { return $a + $b; } int int movl (address of a), %eax movl (address of b), %ebx addl %ebx, %eax OK Enough, Let's compile a function: _add_int_int(int a, int b)
  • 54. libjit http://www.gnu.org/software/libjit/ LibJIT is a library that provides generic Just-In-Time compiler functionality independent of any particular byte-code, language, or runtime.
  • 55. int mul_add(int x, int y, int z) { return x * y + z; }
  • 56. #include <jit/jit.h> jit_context_t context; ... context = jit_context_create(); jit_context_build_start(context);
  • 57. jit_function_t function; ... function = jit_function_create(context, signature);
  • 58. jit_type_t params[3]; jit_type_t signature; ... params[0] = jit_type_int; params[1] = jit_type_int; params[2] = jit_type_int; signature = jit_type_create_signature (jit_abi_cdecl, jit_type_int, params, 3, 1);
  • 59. jit_value_t x, y, z; ... x = jit_value_get_param(function, 0); y = jit_value_get_param(function, 1); z = jit_value_get_param(function, 2);
  • 60. jit_value_t temp1, temp2; ... temp1 = jit_insn_mul(function, x, y); temp2 = jit_insn_add(function, temp1, z); jit_insn_return(function, temp2);
  • 62.
  • 63. jitfu php extension https://github.com/krakjoe/jitfu Creating native instructions in PHP since 2014. JIT-Fu is a PHP extension that exposes an OO API for the creation of native instructions to PHP userland, using libjit. Joe Watkins @krakjoe
  • 64. <?php use JITFUContext; use JITFUType; use JITFUSignature; use JITFUFunc; use JITFUValue; $context = new Context(); $integer = Type::of(Type::int); $function = new Func($context, new Signature($integer, $integer, $integer), function($args) use($integer) { $this->doReturn( $this->doAdd($this->doMul($args[0], $args[1), $args[2]) ); });
  • 66. You can get it through phpbrew phpbrew ext install github:krakjoe/jitfu -- --with-libjit=/opt/local
  • 68. PHPPHP https://github.com/ircmaxell/PHPPHP A PHP VM implementation written in PHP. This is a basic VM implemented in PHP using the AST generating parser developed by @nikic Anthony Ferrara @ircmaxell
  • 69. recki-ct https://github.com/google/recki-ct Recki-CT is a set of tools that implement a compiler for PHP, and is written in PHP! Specifically, Recki-CT compiles a subset of PHP code. The subset is designed to allow a code base to be statically analyzed. Anthony Ferrara @ircmaxell
  • 71. 2. High Level Code Generation
  • 73. Compile PHP to Faster PHP
  • 74. CodeGen github.com/c9s/CodeGen CodeGen transforms your dynamic calls to static code
  • 77. <?php use ConfigKitConfigCompiler; use ConfigKitConfigLoader; // get PH_ROOT from phifty-core defined( 'PH_ROOT' ) || define( 'PH_ROOT', getcwd() ); defined( 'PH_APP_ROOT' ) || define( 'PH_APP_ROOT' , getcwd() ); defined( 'DS' ) || define( 'DS' , DIRECTORY_SEPARATOR ); function initConfigLoader() { // We load other services from the definitions in config file // Simple load three config files (framework.yml, database.yml, application.yml) $loader = new ConfigLoader; if ( file_exists( PH_APP_ROOT . '/config/framework.yml') ) { $loader->load('framework', PH_APP_ROOT . '/config/framework.yml'); } // This is for DatabaseService if ( file_exists( PH_APP_ROOT . '/db/config/database.yml') ) { $loader->load('database', PH_APP_ROOT . '/db/config/database.yml'); } elseif ( file_exists( PH_APP_ROOT . '/config/database.yml') ) { $loader->load('database', PH_APP_ROOT . '/config/database.yml'); } // Config for application, services does not depends on this config file. if ( file_exists( PH_APP_ROOT . '/config/application.yml') ) { $loader->load('application', PH_APP_ROOT . '/config/application.yml'); } // Only load testing configuration when environment // is 'testing' if ( getenv('PHIFTY_ENV') === 'testing' ) { if ( file_exists( PH_APP_ROOT . '/config/testing.yml' ) ) { $loader->load('testing', ConfigCompiler::compile(PH_APP_ROOT . '/config/testing.yml') ); } } return $loader; } A lot of dynamic checking
  • 78. <?php $kernel = new PhiftyKernel; $kernel->prepare(); // prepare constants $composerLoader = require PH_ROOT . '/vendor/autoload.php'; $kernel->registerService( new PhiftyServiceClassLoaderService(getSplClassLoader())); $configLoader = initConfigLoader(); $kernel->registerService( new PhiftyServiceConfigService($configLoader)); $kernel->registerService( new PhiftyServiceEventService ); // if the framework config is defined. if ( $configLoader->isLoaded('framework') ) { // we should load database service before other services // because other services might need database service if ( $configLoader->isLoaded('database') ) { $kernel->registerService( new PhiftyServiceDatabaseService ); } if ( $appconfigs = $kernel->config->get('framework','Applications') ) { foreach ($appconfigs as $appname => $appconfig) { $kernel->classloader->addNamespace( array( $appname => array( PH_APP_ROOT . '/applications' , PH_ROOT . '/applications' ) )); } } if ( $services = $kernel->config->get('framework','Services') ) { foreach ($services as $name => $options) { // not full qualified classname $class = ( false === strpos($name,'') ) ? ('PhiftyService' . $name) : $name; $kernel->registerService( new $class , $options ); } } } $kernel->init(); Dynamic initialization
  • 79. ~1000 lines to bootstrap
  • 81. public function __construct($basePath = null) { $this->registerBaseBindings(); $this->registerBaseServiceProviders(); $this->registerCoreContainerAliases(); if ($basePath) { $this->setBasePath($basePath); } }
  • 82. /** * Register the core class aliases in the container. * * @return void */ public function registerCoreContainerAliases() { $aliases = [ 'app' => ['IlluminateFoundationApplication', 'IlluminateContracts ContainerContainer', 'IlluminateContractsFoundationApplication'], 'auth' => 'IlluminateAuthAuthManager', 'auth.driver' => ['IlluminateAuthGuard', 'IlluminateContractsAuthGuard'], 'auth.password.tokens' => 'IlluminateAuthPasswordsTokenRepositoryInterface', 'url' => ['IlluminateRoutingUrlGenerator', 'IlluminateContractsRouting UrlGenerator'], ..... 20 lines cut ..... 'validator' => ['IlluminateValidationFactory', 'IlluminateContracts ValidationFactory'], 'view' => ['IlluminateViewFactory', 'IlluminateContractsViewFactory'], ]; foreach ($aliases as $key => $aliases) { foreach ((array) $aliases as $alias) { $this->alias($key, $alias); } } }
  • 83. public function detectEnvironment(Closure $callback) { $args = isset($_SERVER['argv']) ? $_SERVER['argv'] : null; return $this['env'] = (new EnvironmentDetector())->detect($callback, $args); }
  • 84. IlluminateFoundationBootstrapConfigureLogging ~120 lines IlluminateFoundationBootstrapDetectEnvironment ~ 29 lines IlluminateFoundationBootstrapHandleExceptions IlluminateFoundationBootstrapLoadConfiguration IlluminateFoundationBootstrapRegisterFacades IlluminateFoundationBootstrapRegisterProviders
  • 85. ~3000 lines of code to bootstrap an application
  • 86. Using CodeGen to reduce checks and remove conditions
  • 87. Declaring Block use CodeGenBlock; use CodeGenComment; use CodeGenCommentBlock; $block = new Block; $block[] = '<?php'; $block[] = new CommentBlock([ "This file is auto-generated through 'bin/phifty bootstrap' command.", "Don't modify this file directly", "", "For more information, please visit https://github.com/c9s/Phifty", ]);
  • 88. Declaring Require Statement // Generates: $kernel->registerService(new PhiftyServiceProvider EventServiceProvider()); $block[] = new Comment('The event service is required for every component.'); $block[] = new RequireClassStatement('PhiftyServiceProviderEventServiceProvider'); $block[] = new Statement(new MethodCall('$kernel', 'registerService', [ new NewObject('PhiftyServiceProviderEventServiceProvider'), ]));
  • 89. Declaring Conditional Statement $stmt = new ConditionalStatement($foo == 1, '$foo = 1'); $stmt->when($foo == 2, function() { return '$foo = 2;'; }); $stmt->when($foo == 3, function() { return '$foo = 3;'; });
  • 90. require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/ActionServiceProvider.php'; $kernel->registerService(new PhiftyServiceProviderActionServiceProvider(array ( 'DefaultFieldView' => 'ActionKitFieldViewBootstrapFieldView', ))); require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/PuxRouterServiceProvider.php'; $kernel->registerService(new PhiftyServiceProviderPuxRouterServiceProvider(array ())); require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/LibraryServiceProvider.php'; $kernel->registerService(new PhiftyServiceProviderLibraryServiceProvider(array ())); require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/ViewServiceProvider.php'; $kernel->registerService(new PhiftyServiceProviderViewServiceProvider(array ( 'Backend' => 'twig', 'Class' => 'AppViewPageView', ))); require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/MailerServiceProvider.php'; $kernel->registerService(new PhiftyServiceProviderMailerServiceProvider(array ( 'Transport' => 'MailTransport', ))); require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/MongodbServiceProvider.php'; $kernel->registerService(new PhiftyServiceProviderMongodbServiceProvider(array ( 'DSN' => 'mongodb:// localhost',))); require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/CacheServiceProvider.php'; $kernel->registerService(new PhiftyServiceProviderCacheServiceProvider(array ())); require '___/___/vendor/corneltek/phifty-core/src/Phifty/ServiceProvider/LocaleServiceProvider.php'; $kernel->registerService(new PhiftyServiceProviderLocaleServiceProvider(array ( 'Directory' => 'locale', 'Default' => 'zh_TW', 'Domain' => '___', 'Langs' => array ( 0 => 'en', 1 => 'zh_TW', ), )));
  • 91. Integrating PHP Parser for CodeGen with Annotation
  • 93. PHP-Parser https://github.com/nikic/PHP-Parser a PHP 5.2 to PHP 5.6 parser written in PHP. Its purpose is to simplify static code analysis and manipulation.
  • 94. // @codegen if ($environment == "development") { $handler = new DevelopmentHandler; } else { $handler = new ProductionHandler; }
  • 95. $handler = new DevelopmentHandler;
  • 97. <?php namespace LazyRecordSchemaFactory; use ClassTemplateTemplateClassFile; use ClassTemplateClassFile; use LazyRecordSchemaSchemaInterface; use LazyRecordSchemaDeclareSchema; use DoctrineCommonInflectorInflector; class BaseModelClassFactory { public static function create(DeclareSchema $schema, $baseClass) { $cTemplate = new ClassFile($schema->getBaseModelClass()); $cTemplate->addConsts(array( 'schema_proxy_class' => $schema->getSchemaProxyClass(), 'collection_class' => $schema->getCollectionClass(), 'model_class' => $schema->getModelClass(), 'table' => $schema->getTable(), 'read_source_id' => $schema->getReadSourceId(), 'write_source_id' => $schema->getWriteSourceId(), 'primary_key' => $schema->primaryKey, )); $cTemplate->addMethod('public', 'getSchema', [], [ 'if ($this->_schema) {', ' return $this->_schema;', '}', 'return $this->_schema = LazyRecordSchemaSchemaLoader::load(' . var_export($schema- >getSchemaProxyClass(),true) . ');', ]); $cTemplate->addStaticVar('column_names', $schema->getColumnNames()); $cTemplate->addStaticVar('column_hash', array_fill_keys($schema->getColumnNames(), 1 ) ); $cTemplate->addStaticVar('mixin_classes', array_reverse($schema-
  • 98. <?php namespace UserBundleModel; use LazyRecordBaseModel; class UserBase extends BaseModel { const schema_proxy_class = 'UserBundleModelUserSchemaProxy'; const collection_class = 'UserBundleModelUserCollection'; const model_class = 'UserBundleModelUser'; const table = 'users'; const read_source_id = 'default'; const write_source_id = 'default'; const primary_key = 'id'; public static $column_names = array ( 0 => 'id', 1 => 'password', 2 => 'auth_token', 3 => 'account', 4 => 'confirmed', 5 => 'email', 6 => 'name', 7 => 'cellphone', 8 => 'phone', 9 => 'role', 10 => 'company', 11 => 'receive_email', 12 => 'receive_sms', 13 => 'remark', 14 => 'org_id', ); public static $column_hash = array ( 'id' => 1, 'password' => 1, 'auth_token' => 1, 'account' => 1, 'confirmed' => 1, 'email' => 1,
  • 99. ActionKit github.com/c9s/ActionKit ActionKit handles your PHP web application logics and record relationships
  • 103. use AppActionCreateProduct; $create = new CreateProduct(['name' => 'Product I', 'sn' => 'PN-12345677']); $success = $create->invoke(); The SPL autoloader generates the action class in cache directory automatically. Trigger ActionKit ActionGenerator by SPL autoloader
  • 104. <?php /** This is an auto-generated file, Please DO NOT modify this file directly. */ namespace AppAction; use ActionKitAction; use ActionKitRecordActionBaseRecordAction; use ActionKitRecordActionUpdateRecordAction; class UpdateStore extends UpdateRecordAction { public $recordClass = 'AppModelProduct'; }
  • 106. use ConfigKitConfigLoader; $loader = new ConfigLoader(); if (file_exists($baseDir.'/config/framework.yml')) { $loader->load('framework', $baseDir.'/config/framework.yml'); } // This is for DatabaseService if (file_exists($baseDir.'/db/config/database.yml')) { $loader->load('database', $baseDir.'/db/config/database.yml'); } elseif (file_exists($baseDir.'/config/database.yml')) { $loader->load('database', $baseDir.'/config/database.yml'); }
  • 107. use CodeGenGeneratorAppClassGenerator; use ConfigKitConfigLoader; $configLoader = new ConfigLoader; $configClassGenerator = new AppClassGenerator([ 'namespace' => 'App', 'prefix' => 'App' ]); $configClass = $configClassGenerator->generate($configLoader); $classPath = $configClass->generatePsr4ClassUnder('app'); $block[] = new RequireStatement(PH_APP_ROOT . DIRECTORY_SEPARATOR . $classPath);