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