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
)
)
)
$foo
$$bar
${'foobar'}
${!${''}=barfoo()}
$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);
php7cc [--except=vendor] [--extensions=php,inc,lib] src/
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 a
future 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