php 7 evolution

87
@felixgomezlopez PHP 7 Evolution @felixgomezlopez

Upload: felix-gomez-lopez

Post on 16-Feb-2017

522 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Php 7 evolution

@felixgomezlopez

PHP 7 Evolution

@felixgomezlopez

Page 2: Php 7 evolution

@felixgomezlopez

Page 3: Php 7 evolution
Page 4: Php 7 evolution

@felixgomezlopez

0. CHRONOLOGY

Page 5: Php 7 evolution

@felixgomezlopez

1995-2016 (21 YEARS OF PHP)

Version Release date

Personal Homepage Tools (PHP Tools) Version 1.0

PHP/FI 2

June 8th 1995

November 1997

PHP 3 June 1998

PHP 4 May 2000

PHP 5 July 2004

PHP 5.3/5.4 June 2009

PHP 7 December 2015

= PHP 6 - UNICODE

Page 6: Php 7 evolution

@felixgomezlopez

¿QUÉ FUE DE PHP6?

https://wiki.php.net/rfc/php6

● Intento fallido de salto de versión

● Iniciado en 2005 y finalizado en 2010

● Se integraron features en PHP 5.3 y 5.4

● Después de descartar UTF-16, intl se distribuyó como parte de PHP 5.3

y exponía las funcionalidades de la librería ICU.

● Se llegaron a publicar libros y se dieron charlas, pero nunca vió la luz

Page 7: Php 7 evolution

@felixgomezlopez

CRONOLOGíA PHP (21 AÑOS)

Versión Tiempo de vida

Personal Homepage Tools (PHP Tools) Version 1.0

PHP/FI 2

~ 2 años

~ 1 año

PHP 3 ~ 2 años

PHP 4 ~ 2 años

PHP 5 ~ 11 años

Page 8: Php 7 evolution

@felixgomezlopez

VERSIONES ACTUALES

http://www.php.net/supported-versions.php

Page 9: Php 7 evolution

@felixgomezlopez

PORCENTAJES DE USO

http://w3techs.com/technologies/details/pl-php/all/all

Page 10: Php 7 evolution

@felixgomezlopez@felixgomezlopez

PHP 7

Page 11: Php 7 evolution

@felixgomezlopez

¿SOBRE QUÉ SE BASA?

https://drive.google.com/file/d/0B3UKOMH_4lgBUTdjUGxIZ3l1Ukk/view?usp=sharing

● Refactoring

● Objetivo principal: Alcanzar un nuevo nivel de rendimiento y

hacerlo base para futuras releases

● Separado de la rama principal de PHP en Enero de 2014

● Sin cambios para el usuario (solo cambios internos)

Page 12: Php 7 evolution

@felixgomezlopez

ESTADO DE PHPNG

● Llevó 2 semanas compilar el core

● En dos semanas más podía correr bench.php

● Después de mes y medio compatible con WordPress

● Se abre el proyecto 1 mes después (principios de mayo)

● Se mergea a master como base para PHP7 en Agosto de 2014

Page 13: Php 7 evolution

@felixgomezlopez

ESTADO DE PHPNG EN OCTUBE 2014

Page 14: Php 7 evolution

@felixgomezlopez

ESTADO DE PHPNG EN OCTUBE 2014

Page 15: Php 7 evolution

@felixgomezlopez

Page 16: Php 7 evolution

@felixgomezlopez

Page 18: Php 7 evolution

@felixgomezlopez

USERLAND

PHP 7 CHANGES

INTERNALS

Page 19: Php 7 evolution

@felixgomezlopez@felixgomezlopez

PHP 7: INTERNALS

Page 20: Php 7 evolution

@felixgomezlopez

INTERNALS

CÓDIGO PHP SCANNING

(a.k.a. LEXING)

<?php

echo "Hello World";$a = 1 + 1;echo $a;

<?php

$code = <<<'PHPCODE'<?phpecho "Hello World";$a = 1 + 1;echo $a;PHPCODE;

print_r(token_get_all($code));

TOKENS

Page 21: Php 7 evolution

@felixgomezlopez

Array( [0] => Array ( [0] => 376 [1] => <?php [2] => 1 )

[1] => Array ( [0] => 312 [1] => $a [2] => 2 )

[2] => Array ( [0] => 379 [1] => [2] => 2 )

[3] => =

[4] => Array ( [0] => 379 [1] => [2] => 2 )

[5] => Array ( [0] => 318 [1] => "Hello World" [2] => 2 )

[6] => ; [7] => Array ( [0] => 379 [1] => [2] => 2 )

[8] => Array ( [0] => 319 [1] => echo [2] => 3 )

[9] => Array ( [0] => 379 [1] => [2] => 3 )

[10] => Array ( [0] => 312 [1] => $a [2] => 3 )

[11] => ;)

SCANNING (a.k.a LEXING)

Page 22: Php 7 evolution

@felixgomezlopez

<?php

$code = <<<'CODE'<?php$a = "Hello World";echo $a;CODE;

$tokens = token_get_all($code);

array_walk($tokens, function (&$token) {

if (count($token) > 1) { $token[0] = token_name((int) $token[0]); } });

print_r($tokens);

SCANNING (a.k.a LEXING)

Page 23: Php 7 evolution

@felixgomezlopez

Array( [0] => Array ( [0] => T_OPEN_TAG [1] => <?php [2] => 1 )

[1] => Array ( [0] => T_VARIABLE [1] => $a [2] => 2 )

[2] => Array ( [0] => T_WHITESPACE [1] => [2] => 2 )

[3] => =

[4] => Array ( [0] => T_WHITESPACE [1] => [2] => 2 )

[5] => Array ( [0] => T_CONSTANT_ENCAPSED_STRING [1] => "Hello World" [2] => 2 )

[6] => ; [7] => Array ( [0] => T_WHITESPACE [1] => [2] => 2 )

http://php.net/manual/en/tokens.php

Page 24: Php 7 evolution

@felixgomezlopez

CÓDIGO PHP SCANNING

(a.k.a. LEXING)

PARSINGTokens

● Elimina espacios en blanco ● Se queda con expresiones irreducibles del

conjunto de tokens

PARSING (PHP 5)

<?php

echo "Hello World";$a = 1 + 1;echo $a;

1. mostrar string2. sumar dos números3. guardar el resultado de la operación anterior en una

variable4. mostrar la variable

Page 25: Php 7 evolution

@felixgomezlopez

COMPILING (PHP 5)

CÓDIGO PHP SCANNING

(a.k.a. LEXING)

TokensOPCODES

● ZEND_ECHO 'Hello World'

● ZEND_ADD ~0 1 1

● ZEND_ASSIGN !0 ~0

● ZEND_ECHO !0

<?php

echo "Hello World";$a = 1 + 1;echo $a;

PARSINGmatching and opcode generation

Page 26: Php 7 evolution

@felixgomezlopez

Finding entry points

Branch analysis from position: 0

Jump found. Position 1 = -2

filename: /in/KVrR3

function name: (null)

number of ops: 4

compiled vars: !0 = $a

line #* E I O op fetch ext return operands

-------------------------------------------------------------------------------------

3 0 E > ECHO 'Hello+World'

4 1 ASSIGN !0, 2

5 2 ECHO !0

3 > RETURN 1

Generated using Vulcan Logic Dumper, using php 7.0.0

OPCODE REPRESENTATION EXAMPLE (PHP 7)

<?php

echo "Hello World";$a = 1 + 1;echo $a;

https://github.com/php/php-src/blob/master/Zend/zend_vm_def.h

Page 27: Php 7 evolution

@felixgomezlopez

CÓDIGO PHP SCANNING

(a.k.a. LEXING)

OPCODESPARSING AST

Tokens

Tokens

PHP 7: ABSTRACT SYNTAX TREE (AST)

https://es.wikipedia.org/wiki/%C3%81rbol_de_sintaxis_abstracta

Page 28: Php 7 evolution

@felixgomezlopez

PHP 7: VENTAJAS ABSTRACT SYNTAX TREE (AST)

● Permite añadir funcionalidades más fácilmente

● Consistencia en la interpretación

● Mejora en rendimiento

● Permite que el lenguaje sea más flexible

Posibilidades “SCI-FI”

● Posibilidad de conversión inversa por análisis de AST->SOURCE CODE

● Posibilidad de generar AST externo para ser compilado por Zend

Engine 3

Page 29: Php 7 evolution

@felixgomezlopez

[$x*2 foreach(range(0,10) as $x)]

http://twig.sensiolabs.org/doc/internals.html

[x*2 for x in range(10)]

PHP 7: POSIBILITIES ABSTRACT SYNTAX TREE (AST)

http://docs.hylang.org/en/latest/

Page 30: Php 7 evolution

@felixgomezlopez

PHP 7: USERLANDNEWS

Page 31: Php 7 evolution

@felixgomezlopez

ENGINE EXCEPTIONS

https://wiki.php.net/rfc/throwable-interfacehttps://wiki.php.net/rfc/engine_exceptions_for_php7

Page 32: Php 7 evolution

@felixgomezlopez

NEW EXCEPTION TREE

Exception

LogicException

RangeException

Throwable

Error

ParseError

TypeError

Page 33: Php 7 evolution

@felixgomezlopez

EXCEPTIONS (NEW ERROR INTERCEPTION)

<?php

function add(int $left, int $right) { return $left + $right;}

try { echo add('left', 'right');} catch (Exception $e) { echo "Captured exception";} catch (Error $e) { // TypeError echo $e->getMessage();}

Page 34: Php 7 evolution

@felixgomezlopez

EXCEPTIONS

<?php

$a=6;

$a->grow();

PHP5

PHP7

PHP Fatal error: Call to a member function grow() on integer

Fatal error: Uncaught Error: Call to a member function grow() on integer

Page 35: Php 7 evolution

@felixgomezlopez

<?php

try {

$a = 6;

$a->grow();

} catch (Error $e) {

echo $e->getMessage();

}

EXCEPTIONS

Call to a member function grow() on integer

Page 36: Php 7 evolution

@felixgomezlopez

EXCEPTIONS

<?php

try {

foo();

} catch (Error $e) {

var_dump($e);

}

object(Error)#1 (7) {

["message":protected]=>

string(43) "Call to a member function grow() on

integer"

["string":"Error":private]=>

string(0) ""

["code":protected]=>

int(0)

["file":protected]=>

string(27) "/home/vagrant/Lab/index.php"

["line":protected]=>

int(5)

["trace":"Error":private]=>

array(0) {

}

["previous":"Error":private]=>

NULL

}

Page 37: Php 7 evolution

@felixgomezlopez

RETURN TYPE DECLARATIONS https://wiki.php.net/rfc/return_types

Page 38: Php 7 evolution

@felixgomezlopez

RETURN TYPE DECLARATIONS (TIPOS DE RETORNO)

function foo(): array {

return [];

}

Page 39: Php 7 evolution

@felixgomezlopez

RETURN TYPE DECLARATIONS (TIPOS DE RETORNO)

<?php

// Returned type does not match the type declaration

function get_config(): array {

return 42;

}

get_config();

Fatal error: Uncaught TypeError: Return value of get_config() must be of the

type array, integer returned in /home/vagrant/Lab/index.php:6

Stack trace:

#0 /home/vagrant/Lab/index.php(9): get_config()

#1 {main}

thrown in /home/vagrant/Lab/index.php on line 6

Page 40: Php 7 evolution

@felixgomezlopez

SCALAR TYPE DECLARATIONS

https://wiki.php.net/rfc/scalar_type_hints_v5

Page 41: Php 7 evolution

@felixgomezlopez

SCALAR TYPE DECLARATIONS

<?php

declare(strict_types=1);

function add(float $a, float $b): float {

return $a + $b;

}

add(1, 2); // float(3)

int a float es la única conversión permitida

Page 42: Php 7 evolution

@felixgomezlopez

SCALAR TYPE DECLARATIONS

<?php

function add(int $val1, int $val2) {

return $val1 + $val2;

}

$a = add("2", "2");

var_dump($a); // int(4)

Page 43: Php 7 evolution

@felixgomezlopez

SCALAR TYPE DECLARATIONS

<?php

declare(strict_types = 1);

function add(int $val1, int $val2) {

return $val1 + $val2;

}

$a = add("2", "2");

var_dump($a);

Page 44: Php 7 evolution

@felixgomezlopez

Fatal error: Uncaught TypeError: Argument 1 passed to add()

must be of the type integer, string given, called in

/home/vagrant/Lab/index.php on line 10 and defined in

/home/vagrant/Lab/index.php:5

Stack trace:

#0 /home/vagrant/Lab/index.php(10): add('2', '2')

#1 {main}

thrown in /home/vagrant/Lab/index.php on line 5

SCALAR TYPE DECLARATIONS

Page 45: Php 7 evolution

@felixgomezlopez

<?php

declare(strict_types = 1);

function foo() : bool {

return 1;

}

$a = foo();

var_dump($a);

SCALAR TYPE DECLARATIONS

Page 46: Php 7 evolution

@felixgomezlopez

SCALAR TYPE DECLARATIONS

Fatal error: Uncaught TypeError: Return value of foo() must

be of the type boolean, integer returned in

/home/vagrant/Lab/index.php:5

Stack trace:

#0 /home/vagrant/Lab/index.php(8): foo()

#1 {main}

thrown in /home/vagrant/Lab/index.php on line 5

Page 47: Php 7 evolution

@felixgomezlopez

NULL COALESCE OPERATOR(OPERADOR DE FUSIÓN DE NULL)

https://wiki.php.net/rfc/isset_ternary

Page 48: Php 7 evolution

@felixgomezlopez

NULL COALESCE OPERATOR - ANTERIOR ALTERNATIVA

if (isset($_GET['user'])) {

$user = $_GET['user'];

} else {

$user = 'nobody';

}

$user = isset($_GET['user']) ? $_GET['user'] : 'nobody';

Page 49: Php 7 evolution

@felixgomezlopez

NULL COALESCE OPERATOR (FUSIÓN DE NULL)

$x = ['foo' => 'a', 'bar' => 'b'];

var_dump($x['baz'] ?? $x['bar'] ?? $x['foo'] ?? 'none');

// string(1) "b"

$user = $_GET['user'] ?? 'nobody';

$user = isset($_GET['user']) ? $_GET['user'] : 'nobody';

Page 50: Php 7 evolution

@felixgomezlopez

SPACESHIP (a.k.a. COMBINED COMPARISON) OPERATOR

https://wiki.php.net/rfc/combined-comparison-operator

Page 51: Php 7 evolution

@felixgomezlopez

SPACESHIP OPERATOR

// Integersecho 1 <=> 1; // 0echo 1 <=> 2; // -1echo 2 <=> 1; // 1

// Floatsecho 1.5 <=> 1.5; // 0echo 1.5 <=> 2.5; // -1echo 2.5 <=> 1.5; // 1

// Stringsecho "a" <=> "a"; // 0echo "a" <=> "b"; // -1echo "b" <=> "a"; // 1

echo "a" <=> "aa"; // -1echo "zz" <=> "aa"; // 1

// Arraysecho [] <=> []; // 0echo [1, 2, 3] <=> [1, 2, 3]; // 0echo [1, 2, 3] <=> []; // 1echo [1, 2, 3] <=> [1, 2, 1]; // 1echo [1, 2, 3] <=> [1, 2, 4]; // -1

// Objects// Only values are compared$a = (object) ["a" => "b"];$b = (object) ["b" => "b"];echo $a <=> $b; // 0

Page 52: Php 7 evolution

@felixgomezlopez

ANONYMOUS CLASSEShttps://wiki.php.net/rfc/anonymous_classes

Page 53: Php 7 evolution

@felixgomezlopez

ANONYMOUS CLASSES

<?php

var_dump(new class($i) { public function __construct($i) { $this->i = $i; }});

<?php

class Foo {}$child = new class extends Foo {};

var_dump($child instanceof Foo); // true

Page 54: Php 7 evolution

@felixgomezlopez

ANONYMOUS CLASSES

<?php

trait Foo { public function someMethod() { return "bar"; }}

$anonClass = new class { use Foo;};

var_dump($anonClass->someMethod()); // string(3) "bar"

Page 55: Php 7 evolution

@felixgomezlopez

ANONYMOUS CLASSES

<?php

// PHP 5.xclass MyLogger { public function log($msg) { print_r($msg . "\n"); }}

$pusher->setLogger( new MyLogger() );

// New Hotness$pusher->setLogger(new class { public function log($msg) { print_r($msg . "\n"); }});

Page 56: Php 7 evolution

@felixgomezlopez

GROUP USE DECLARATIONShttps://wiki.php.net/rfc/group_use_declarations

Page 57: Php 7 evolution

@felixgomezlopez

GROUP USE DECLARATIONS

use Symfony\Component\Form\Form;

use Symfony\Component\Form\FormError;

use Talk\TalkDb;

use Talk\TalkApi;

use User\UserDb;

use User\UserApi;

use Symfony\Component\Form\{Form, FormError};

use Talk\{TalkDb, TalkApi};

use User\{UserDb, UserApi};

PHP5

PHP7

Page 58: Php 7 evolution

@felixgomezlopez

UNIFORM VARIABLE SYNTAXhttps://wiki.php.net/rfc/uniform_variable_syntax

Page 59: Php 7 evolution

@felixgomezlopez

UNIFORM VARIABLE SYNTAX

echo $car->$engine['model'];

// PHP 5

echo $car->{$engine['model']};

// PHP 7

echo {$car->$engine}['model'];

Page 60: Php 7 evolution

@felixgomezlopez

UNIFORM VARIABLE SYNTAX (CONT.)

// old meaning // new meaning

$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz']

$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']

$foo->$bar['baz']() $foo->{$bar['baz']}() ($foo->$bar)['baz']()

Foo::$bar['baz']() Foo::{$bar['baz']}() (Foo::$bar)['baz']()

Ante la duda paréntesis!

Page 61: Php 7 evolution

@felixgomezlopez

$foo()['bar']()

[$obj1, $obj2][0]->prop

getStr(){0}

// support nested ::

$foo['bar']::$baz

$foo::$bar::$baz

$foo->bar()::baz()

// support nested ()

foo()()

$foo->bar()()

Foo::bar()()

$foo()()

UNIFORM VARIABLE SYNTAX (CONT.)

Page 62: Php 7 evolution

@felixgomezlopez

UNIFORM VARIABLE SYNTAX (CONT.)

// support operations on arbitrary (...) expressions

(...)['foo']

(...)->foo

(...)->foo()

(...)::$foo

(...)::foo()

(...)()

// two more practical examples for the last point

(function() { ... })()

($obj->closure)()

Page 63: Php 7 evolution

@felixgomezlopez

GENERATOR DELEGATION & RETURN VALUEShttps://wiki.php.net/rfc/generator-delegation

Page 64: Php 7 evolution

@felixgomezlopez

GENERATOR RETURN VALUES

<?php

function foo() { yield 1; yield 2; return 42;}

$bar = foo();foreach ($bar as $element) { echo $element, "\n";}

var_dump($bar->getReturn());

// 1// 2// int(42)

Page 65: Php 7 evolution

@felixgomezlopez

GENERATOR DELEGATION

<?php

function myGeneratorFunction($foo) { $bar = yield from factoredComputation1($foo); $baz = yield from factoredComputation2($bar);

return $baz;}

function factoredComputation1($foo) { yield $foo + 1; yield $foo + 2;}

function factoredComputation2($bar) { yield $bar + 3; yield $bar + 4;}

foreach (myGeneratorFunction(0) as $v) { echo $v;}

// 1234

Page 66: Php 7 evolution

@felixgomezlopez

UNICODE SCAPE SYNTAXhttps://wiki.php.net/rfc/unicode_escape

Page 67: Php 7 evolution

@felixgomezlopez

UNICODE SCAPE SYNTAX

echo "We \u{2665} PHPVigo\n";

We ♥ PHPVigo

echo "\u{1F602}"; // outputs

echo "\u{202E}Reversed text";

// outputs txet desreveR

Page 68: Php 7 evolution

@felixgomezlopez

REMOVE ALTERNATIVE PHP TAGS

https://wiki.php.net/rfc/remove_alternative_php_tags

Page 69: Php 7 evolution

@felixgomezlopez

REMOVE ALTERNATIVE PHP TAGS

● <% opening tag

● <%= opening tag with echo

● %> closing tag

● (<script\s+language\s*=\s*(php|"php"|'php')\s*>)i

opening tag

● (</script>)i closing tag

Page 70: Php 7 evolution

@felixgomezlopez

REMOVE ALTERNATIVE PHP TAGS

<script type="php">

// No funciona

</script>

<%

// Tampoco funciona

%>

Page 71: Php 7 evolution

@felixgomezlopez

REMOVE DEAD SAPIS AND EXTENSIONS

https://wiki.php.net/rfc/removal_of_dead_sapis_and_exts

Page 72: Php 7 evolution

@felixgomezlopez

REMOVE DEAD SAPIS AND EXTENSIONS

Se eliminan las APIS de servidor no portadas o discontinuadas

● sapi/aolserver● sapi/apache● sapi/apache_hooks● sapi/apache2filter● sapi/caudium● sapi/continuity● sapi/isapi● sapi/milter● sapi/nsapi

● sapi/phttpd● sapi/pi3web● sapi/roxen● sapi/thttpd● sapi/tux● sapi/webjames● ext/mssql● ext/mysql● ext/sybase_ct● ext/ereg

Muchas de ellas se migran a PECL

Page 73: Php 7 evolution

@felixgomezlopez

REMOVE DEPRECATED FUNCIONALITY

https://wiki.php.net/rfc/remove_deprecated_functionality_in_php7

Page 74: Php 7 evolution

@felixgomezlopez

REMOVE DEPRECATED FUNCIONALITY

Las más notables son:

● Extensión mysql (ext/mysql) -> PDO, mysqli

● Extensión ereg (ext/ereg) -> PCRE

● Asignación de new por referencia $a = & new A;

Page 75: Php 7 evolution

@felixgomezlopez

“REMOVAL” OF PHP4 CONSTRUCTORS

https://wiki.php.net/rfc/remove_deprecated_functionality_in_php7

Page 76: Php 7 evolution

@felixgomezlopez

<?phpclass Filter{

// PHP 5: filter is a constructor// PHP 7: filter is a constructor and E_DEPRECATED is raised// PHP 8: filter is a normal method and is not a constructor; no E_DEPRECATED is raised

function filter($a) {}}

$filter = new ReflectionMethod('Filter', 'filter');

// PHP 5: bool(true)// PHP 7: bool(true)// PHP 8: bool(false)var_dump($filter->isConstructor());

“REMOVAL” OF PHP4 CONSTRUCTORS

Page 77: Php 7 evolution

@felixgomezlopez

<?php

// function filter is not used as constructor in PHP 5+

class Filter

{

// PHP 5: E_STRICT "Redefining already defined

constructor"

// PHP 7: No error is raised

// PHP 8: No error is raised

function __construct() {}

function filter($a) {}

}

“REMOVAL” OF PHP4 CONSTRUCTORS

Page 78: Php 7 evolution

@felixgomezlopez

<?php

// function filter is not used as constructor in PHP 5+

class Filter {

function __construct() {}

// PHP 5.0.0 - 5.2.13, 5.3.0 - 5.3.2: E_STRICT "Redefining

already defined constructor"

// PHP 5.2.14 - 5.2.17, 5.3.3 - 5.6: No error is raised

// PHP 7: No error is raised

// PHP 8: No error is raised

function filter($a) {}

}

REMOVAL OF PHP4 CONSTRUCTORS

Page 79: Php 7 evolution

@felixgomezlopez

class Filter{ // PHP 5: filter is a constructor // PHP 7: filter is a constructor and E_DEPRECATED is raised // PHP 8: filter is a normal method and is not a constructor; no E_DEPRECATED is raised function filter() {}}

class FilterX extends Filter{

function __construct(){ // PHP 5: Filter::filter is called; no error // PHP 7: Filter::filter is called; no error // PHP 8: "Fatal error: Cannot call constructor" parent::__construct(); } }

new FilterX();

“REMOVAL” OF PHP4 CONSTRUCTORS

Page 80: Php 7 evolution

@felixgomezlopez

BUGFIX: MULTIPLE DEFAULT CLAUSES IN SWITCH RAISE ERRORhttps://wiki.php.net/rfc/switch.default.multiple

Page 81: Php 7 evolution

@felixgomezlopez

MULTIPLE DEFAULT CLAUSES IN SWITCH RAISE ERROR

switch ($expr) {

default:

neverExecuted();

break;

default:

executed();

}

Page 82: Php 7 evolution

@felixgomezlopez

BUGFIX: FOREACH BEHAVIOURhttps://wiki.php.net/rfc/php7_foreach

Page 83: Php 7 evolution

@felixgomezlopez

BUGFIX FOREACH BEHAVIOUR

<?php

$a = [1,2,3];

foreach($a as $v) { echo $v . " - " . current($a) . "\n";}

// PHP5// 1 - 2// 2 - 2// 3 - 2

// PHP7// 1 - 1// 2 - 1// 3 - 1

Page 84: Php 7 evolution

@felixgomezlopez

PHP 7: TESTS

Page 85: Php 7 evolution

@felixgomezlopez

https://hub.docker.com/_/php/

https://github.com/rlerdorf/php7dev

https://3v4l.org/

https://github.com/sstalle/php7cc

TESTS

Page 86: Php 7 evolution

@felixgomezlopez

QUESTIONS?

THANKS!

Page 87: Php 7 evolution

@felixgomezlopez

www.opsou.com www.pedrofigueras.com