On Github jolicode / php7cc-conf
Rdv AFUP - 23 fev 2016 - Loïck Piera
Développeur web chez
Standard, non ?
function foo(Foo $foo) { $foo->bar(); }
VS
function bar($bar) { $method = 'yolo_' . $this->getMethodName(); $$bar->$method(); }
Beaucoup en ont peur
On va voir que c'est simple à manipuler...
$b = $a + 5;
Assignment ( var: Variable ( name: b ) expression: Binary Operation Plus ( left: Variable ( name: a ) right: Scalar Left Value ( value: 5 ) ) )
$parser = new \PhpParser\Parser(new \PhpParser\Lexer()); foreach ($files as $file) { try { $content = file_get_contents($file); if (!empty($content)) { echo sprintf('Parsing du fichier "%s"', $file); // Parsing et création des AST $stmts = $parser->parse($content); // Traversée des AST // ... } } catch (\PhpParser\Error $e) { echo 'Parse Error: ', $e->getMessage(); } }
$parser = new \PhpParser\Parser(new \PhpParser\Lexer()); $traverser = new \PhpParser\NodeTraverser(); $traverser->addVisitor(...); // … // Parsing et création de l'AST $stmts = $parser->parse($content); // Traversée des AST $traverser->traverse($stmts);
Interface \PhpParser\NodeVisitor :
public function beforeTraverse(array $nodes); public function enterNode(\PhpParser\Node $node); public function leaveNode(\PhpParser\Node $node); public function afterTraverse(array $nodes);
Redéfinition de classes globales (Error, TypeError, ReflectionType, etc) Multiple default cases Constructeur PHP 4 Bitwise shift par un nombre négatif Option 'salt' dans password_hash() Nom de paramètre de fonction dupliqué Classe nommée bool, int, float, etc Utilisation de $HTTP_RAW_POST_DATA String contenant une notation hexadecimal invalide Redéfinition de fonctions globales (intdiv, random_int, etc) Appel de fonctions supprimées (mysql_*, mssql_*, mcrypt_*, etc) New assignement par référence Eval modifier 'e' dans preg_replace
Et bien d'autres...
class Foo {} $foo =& new Foo();
PHP 5 :
Deprecated: Assigning the return value of new by reference is deprecated in /path/to/script.php on line 3
PHP 7 :
Parse error: syntax error, unexpected 'new' (T_NEW) in /path/to/script.php on line 3
use PhpParser\Node\Expr; class NewAssignmentByReferenceVisitor extends AbstractVisitor { public function enterNode(\PhpParser\Node $node) { if ($node instanceof Expr\AssignRef && $node->expr instanceof Expr\New_) { $this->addContextMessage('Result of new is assigned by reference', $node); } } }
function foo($bar, $bar) {}
PHP 5 :
OK
PHP 7 :
Fatal error: Redefinition of parameter $bar in /path/to/script.php on line 2
use PhpParser\Node; class DuplicateFunctionParameterVisitor extends AbstractVisitor { public function enterNode(Node $node) { if (!$node instanceof Node\FunctionLike) return; $parametersNames = array(); foreach ($node->getParams() as $parameter) { $currentParameterName = $parameter->name; if (!isset($parametersNames[$currentParameterName])) { $parametersNames[$currentParameterName] = false; } elseif (!$parametersNames[$currentParameterName]) { $this->addContextMessage( sprintf('Duplicate function parameter name "%s"', $currentParameterName), $node ); $parametersNames[$currentParameterName] = true; } } } }
class Foo { public function Foo() {} }
PHP 5 :
OK
PHP 7 :
Conservés mais dépréciés et limité aux cas existants avant PHP 5
Deprecated: Methods with the same name as their class will not be constructors in afuture version of PHP; Foo has a deprecated constructor in /path/to/script.php on line 3
class PHP4ConstructorVisitor extends AbstractVisitor { public function enterNode(Node $node) { if (!$node instanceof Node\Stmt\Class_) return; $currentClassName = $node->name; $hasPhp4Constructor = $hasPhp5Constructor = false; $php4ConstructorNode = null; // Anonymous class can't use php4 constructor by definition if (empty($currentClassName)) return; // Checks if class is namespaced if (count($node->namespacedName->parts) > 1) return; foreach ($node->stmts as $stmt) { if (!$stmt instanceof Node\Stmt\ClassMethod) continue; if ($stmt->name === '__construct') $hasPhp5Constructor = true; if ($stmt->name === $currentClassName) { $hasPhp4Constructor = true; $php4ConstructorNode = $stmt; } } if ($hasPhp4Constructor && !$hasPhp5Constructor) { $this->addContextMessage('PHP 4 constructors deprecated', $php4ConstructorNode); } } }
Viens faire de la trottinette avec nous