php experience 2016 - [palestra] keynote: php-7
TRANSCRIPT
PHP 7Guilherme Blanco
Guilherme Blanco
http://github.com/guilhermeblanco
@guilhermeblanco
Guilherme Blanco
http://github.com/guilhermeblanco
@guilhermeblanco
http://hhvm.com/blog/9293/lockdown-results-and-hhvm-performance
Agenda• Mudanças para o usuário
• Mudanças internas
• PHP.NEXT
Mudanças para o usuário• Quebras de compatibilidade
• Novos operadores
• Erros e exceções
• Indução de tipo escalar (Scalar type hint)
• Declaração de tipo de retorno (Return type hint)
• Classes anônimas (Anonymous classes)
• Palavras-chave semi-reservadas
Quebras de compatibilidade
<% /* ... */ %>
<%= /* ... */ %>
<script language="php">/* ... */</script>
<? /* ... */ ?>
<?= /* ... */ ?>
<?php /* ... */ ?>
• Tags alternativas do PHP
Quebras de compatibilidade• Construtores do PHP 4
1 class Post { 2 public function post() { 3 echo 'post'; 4 } 5 }
$post = new Post();
$post = new \Domain\Post();
1 namespace Domain { 2 class Post { 3 public function post() { 4 echo 'post'; 5 } 6 } 7 }
Quebras de compatibilidade• Mudanças de sintaxe (Uniform variable syntax)
• Novas combinações de operadores
$foo()['bar']() [$obj1, $obj2][0]->prop $foo->bar()::baz() $foo->bar()() (function () {})()
Quebras de compatibilidade• Mudanças de sintaxe (Uniform variable syntax)
• Acesso indireto à variáveis, propriedades e métodos
Expressão Interpretação no PHP 5 Interpretação no PHP 7
$$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']()
Quebras de compatibilidade• Server APIs removidas:
aolserver, apache, apache_hooks, apache2filter, caudium, continuity, isapi, milter, nsapi, phttpd, pi3web, roxen, thttpd, tux, webjames
• Extensões depreciadas (PECL): ereg, mssql, mysql, sybase_ct
Novos operadores• Null coalesce operator (??)
• Spaceship operator (<=>)
• Group use
• Unicode escape syntax (\u)
Novos operadores• Null coalesce operator (??)
$page = $_GET['page'] ?: 1;
if (isset($_GET['page'])) { $page = $_GET['page']; } else { $page = 1; }
$page = isset($_GET['page']) ? $_GET['page'] : 1 ;
$page = $_GET['page'] ?? 1;
Novos operadores• Operador de comparação combinado (Spaceship operator) (<=>)
1 // Integers 2 echo 1 <=> 1; // 0 3 echo 2 <=> 1; // 1 4 echo 1 <=> 2; // -1 5 6 // Floats 7 echo 1.5 <=> 1.5; // 0 8 echo 2.5 <=> 1.5; // 1 9 echo 1.5 <=> 2.5; // -1 10 11 // Strings 12 echo 'a' <=> 'a'; // 0 13 echo 'z' <=> 'a'; // 1 14 echo 'a' <=> 'z'; // -1 15 16 echo 'zz' <=> 'aa'; // 1 17 echo 'a' <=> 'aa'; // -1
Novos operadores• Group use
use \Eblock\Domain\Directory\Entity\{ Consigner, Location as ConsignerLocation, User };
use \Eblock\Domain\Directory\{ DTO\{ Consigner\Update as UpdateConsigner }, Entity\{ Consigner, Location, User } };
Novos operadores• Unicode escape syntax (\u)
❤ (0x2764)
// <3 no PHP 5 $char = html_entity_decode('𐂄', 0, 'UTF-8'); $char = mb_convert_encoding('𐂄', 'UTF-8', 'HTML-ENTITIES'); $char = json_decode('"\\u2764"');
// <3 no PHP 7 $char = "\u2764";
Erros e exceções• Usuário pode capturar qualquer chamada que possa gerar erros fatais
• A maioria dos error E_RECOVERABLE viraram Exceptions
• Erros E_STRICT foram re-classificados como E_WARN e E_NOTICE
• Erros fatais são ou herdam a classe "Error"
• Erros de análise sintática geram "ParseError"
• Ambos "Error" e "Exception" implementam a interface "Throwable"
Erros e exceções
Erros e exceções 1 echo 'PHP ' . phpversion() . PHP_EOL; 2 3 try { 4 $foo = new foo(); 5 } catch (\Exception $e) { 6 echo 'I am an exception: ' . $e->getMessage() . PHP_EOL; 7 } catch (\Error $e) { 8 echo 'I am an error: ' . $e->getMessage() . PHP_EOL; 9 } catch (\Throwable $t) { 10 echo 'I am throwable: ' . $t->getMessage() . PHP_EOL; 11 } 12 13 // PHP 5.6.19 14 // Fatal error: Class 'foo' not found in 15 // Documents/PHP7/throwable.php on line 5 16 17 // PHP 7.0.4 18 // I am an error: Class 'foo' not found
Indução de tipo escalar• Funciona de duas formas distintas:
• Weak mode (Coercivo)
• Strict (Forte)
declare(strict_types=1);
Indução de tipo escalar
Tipo declarado int float string bool object
int yes yes* yes† yes nofloat yes yes yes† yes nostring yes yes yes yes yes‡bool yes yes yes yes no
* Somente pontos flutuantes não-NaN e entre PHP_INT_MIN e PHP_INT_MAX serão aceitos. † Se for uma string numérica ‡ Somente se o objeto tiver o método __toString()
function setEnabled(bool $enabled) { /* ... */ }
Indução de tipo escalar
1 declare(strict_types=1); 2 3 function welcome(string $name) { 4 echo 'Welcome to the show, ' . $name; 5 } 6 7 welcome('Guilherme'); 8 // Welcome to the show, Guilherme 9 10 welcome(42); 11 // TypeError: Argument 1 passed to welcome() 12 // must be of the type string, integer given
Declaração de tipo de retorno
function getCreator(): UserInterface { return $this->getPost()->getAuthor(); }
function getAuthor(): UserInterface { return 'Guilherme Blanco'; }
getAuthor(); // TypeError: Return value of getAuthor() must be // an instance of UserInterface, string returned
Classes anônimas// Pre PHP 7 class EchoLogger implements LoggerInterface { public function log($message) { echo $message; } }
$application->setLogger(new Logger());
// PHP 7, seu lindo! <3 $application->setLogger(new class () implements LoggerInterface { public function log(string $message) { echo $message; } });
Palavras-chave semi-reservadas• abstract • and • array • as • break • callable • case • catch • class* • clone • const • continue • declare • default • die • do
• global • goto • if • implements • include • include_once • instanceof • insteadof • interface • list • namespace • new • or • parent • print • private
• protected • public • require • require_once • return • self • static • switch • throw • trait • try • use • var • while • xor • yield
• echo • else • elseif • enddeclare • endfor • endforeach • endif • endswitch • endwhile • exit • extends • final • finally • for • foreach • function
Palavras-chave semi-reservadas
1 namespace HTTP 2 { 3 class StatusCode 4 { 5 const CONTINUE = 100; 6 const SWITCHING_PROTOCOLS = 101; 7 // ... 8 } 9 }
Palavras-chave semi-reservadas 1 $queryBuilder = $repository->createQueryBuilder('e'); 2 3 $queryBuilder 4 ->where() 5 ->and() 6 ->field('e.projeto') 7 ->not() 8 ->like('%secreto%') 9 ->end() 10 ->field('e.prioridade') 11 ->gt(9) 12 ->end() 13 ->end() 14 ->or() 15 ->field('e.codigo') 16 ->in([4, 5, 6]) 17 ->end() 18 ->end() 19 ->end() 20 ;
Mudanças internas• Árvore de sintaxe abstrata (Abstract Syntax Tree)
• Suporte completo a 64 bits
• Large File Support (LFS)
• Strings maiores que 231
• Suporte a inteiros de 64 bits
• Novo gerenciamento de memória
• ZVALs são alocados na stack
• refcount mais preciso
• Nova implementação de segurança sobre threads
• Thread safety no PHP 5 implicava numa penalização de performance em ~20%
• Otimização de estruturas de dados
Árvore de sintaxe abstrata<?php
$a = 42; $b = 24;
echo $a + $b;
<?php T_OPEN_TAG $a T_VARIABLE = T_EQUALS 42 T_LNUMBER ; T_SEMICOLON $b T_VARIABLE = T_EQUALS 24 T_LNUMBER ; T_SEMICOLON echo T_ECHO $a T_VARIABLE + T_PLUS $b T_VARIABLE ; T_SEMICOLON
lex
ASSIGN $a 42 ASSIGN $b 24 ADD $a $b ~0 ECHO ~0 RETURN 1
parse + compile
Árvore de sintaxe abstrata<?php
$a = 42; $b = 24;
echo $a + $b;
<?php T_OPEN_TAG $a T_VARIABLE = T_EQUALS 42 T_LNUMBER ; T_SEMICOLON $b T_VARIABLE = T_EQUALS 24 T_LNUMBER ; T_SEMICOLON echo T_ECHO $a T_VARIABLE + T_PLUS $b T_VARIABLE ; T_SEMICOLON
lex
stmts
assign assign echo
42 24 +
$a $b $a $b
var var
parse
ASSIGN $a 42 ASSIGN $b 24 ADD $a $b ~0 ECHO ~0 RETURN 1
compile
Otimização de estruturas de dados
• ~20% do tempo gasto no PHP 5 era referente à alocação de memória
• No PHP 7, foi reduzido o número de alocações
• No PHP 7, foi reduzido o consumo de memória
• No PHP 7, foi reduzido o número de indicações
• O motor de execução agora utiliza stack push e gerencia argumentos
• Chamada pra funções foram drasticamente refatoradas
• Variáveis no PHP 7 são cacheadas de forma mais eficiente
• String são refcounted
Otimização de estruturas de dados
• ZVAL no PHP 5 1 typedef union _zvalue_value { 2 long lval; 3 double dval; 4 struct { 5 char *val; 6 int len; 7 } str; 8 HashTable *ht; 9 zend_object_value obj; 10 zend_ast *ast; 11 } zvalue_value;
1 struct _zval_struct { 2 zvalue_value value; 4 zend_uint refcount__gc; 5 zend_uchar type; 6 zend_uchar is_ref__gc; 7 } zval;
ZVAL no PHP 5
valueZVAL
ty
Crédito: Nikita Popov
ZVAL no PHP 5
value (simple):null, bool, int, float
ZVAL
ty
Crédito: Nikita Popov
ZVAL no PHP 5
value (complex):ZVAL
ty
complex data structure:string, array, object
Crédito: Nikita Popov
ZVAL no PHP 5
1 $a = [];
zval *$a value (complex):ZVAL
ty
complex data structure:string, array, object
refcount = 1
Crédito: Nikita Popov
ZVAL no PHP 5
zval *$a
1 $a = []; 2 $b = $a;
value (complex):ZVAL
ty
complex data structure:string, array, object
refcount = 1
Crédito: Nikita Popov
ZVAL no PHP 5
zval *$a
1 $a = []; 2 $b = $a;
value (complex):ZVAL
ty
complex data structure:string, array, object
refcount = 2zval *$b
Crédito: Nikita Popov
1 typedef union _zend_value { 2 zend_long lval; 3 double dval; 4 zend_refcounted *counted; 5 zend_string *str; 6 zend_array *arr; 7 zend_object *obj; 8 zend_resource *res; 9 zend_reference *ref; 10 zend_ast_ref *ast; 11 zval *zv; 12 void *ptr; 13 zend_class_entry *ce; 14 zend_function *func; 15 struct { 16 uint32_t w1; 17 uint32_t w2; 18 } ww; 19 } zend_value;
1 struct _zval_struct { 2 zend_value value; 3 union { 4 struct { 5 ZEND_ENDIAN_LOHI_4( 6 zend_uchar type, 7 zend_uchar type_flags, 8 zend_uchar const_flags, 9 zend_uchar reserved) 10 } v; 11 uint32_t type_info; 12 } u1; 13 union { 14 uint32_t var_flags; 15 uint32_t next; 16 uint32_t cache_slot; 17 uint32_t lineno; 18 uint32_t num_args; 19 uint32_t fe_pos; 20 uint32_t fe_iter_idx; 21 uint32_t access_flags; 22 } u2; 23 } zval;
ZVAL no PHP 7
ZVAL no PHP 7
zval *$a
1 $a = []; 2 $b = $a;
value (complex):ZVAL
tyzval *$b
complex data structure:string, array, object
refcount = 2
Crédito: Nikita Popov
ZVAL no PHP 7
zval *$a
1 $a = []; 2 $b = $a;
zval *$b
complex data structure:string, array, object
refcount = 2
ZVALvalue (complex):
type_info
Crédito: Nikita Popov
ZVAL no PHP 7
$a
1 $a = []; 2 $b = $a;
$b
complex data structure:string, array, object
refcount = 2
value (complex):
type_infovalue (complex):
type_info
Crédito: Nikita Popov
PHP 5 vs. PHP 7 ZVALzval *
value (simple):null, bool, int, float
tyrefcount = 1
1 alocação de memória 1 nível de indireção
40 bytes
value (simple):null, bool, int, float
type_info
sem alocações de memória sem indireções
16 bytes
PHP 5 vs. PHP 7 ZVALzval *
complex data structure: string, array, object
value (complex):
tyrefcount = 1
2 alocações de memória 2 níveis de indireção
40 bytes
complex data structure:string, array, object
refcount = 1
value (complex):
type_info
1 alocação de memória 1 nível de indireção
24 bytes
PHP 5 vs. PHP 7 Objetoszval
object store bucket
object real
tabela de propriedades
valor da propriedade
zval
objeto real +
tabela de propriedades (incluindo valores)
PHP 5 PHP 7
Alocações 2 + 1 / propriedade 1 + 0 / propriedade
Tamanho 96 + 40 / propriedade 48 + 16 / propriedade
Indireções 4 1
PHP.NEXT• Parâmetros nomeados (Named parameters)
• Visibilidade de classes (Class Visibility)
• Tipagem de propriedades (Typed properties)
• Anotações (Annotations)
• Coleções (Collections)
• Estruturas genéricas (Generics)
Perguntas?
Thanks! =)
http://github.com/guilhermeblanco
@guilhermeblanco