When migrating, we often need to review old code and target only the interesting issues. This session will connect the backward incompatibilities and new features to actual location in the code, relying on static analysis to process quickly large code base. Based on the accumulated experience of the tools, we’ll review the issues, diagnose criticality, select the best fixes and prioritize the tasks. All tools will be Open Source, and ready to follow you home for more validation.
7. Living on the edge
http://php.net/manual/en/migration70.php
Online
UPGRADING TO PHP 7
Free Book, PDF
Davey Shafik is RM for PHP 7.1
Lots of blogs and articles
8. Living on the bleeding edge
https://github.com/php/php-src/blob/master/
UPGRADING
https://github.com/php/php-src/blob/master/NEWS
https://wiki.php.net/rfc
http://bugs.php.net/
9.
10.
11.
12. Where does code break?
PHP has 3 phases
syntax
definitions
execution
Checked with phplint
Checked with tests
Checked code review
13. Where will code break?
SyntaxDefinitionsExecution
<?php
function splitNames($fullname, $fullname) {
list($first, $last) = split($fullname, ' ');
}
?>
22. Switch statements may only contain
one default clause
<?php
switch($x) {
case '1' :
break;
default :
break;
default :
break;
case '2' :
break;
}
23. Switch statements may only contain
one default clause
switch($x) {
case 1 :
break;
case 0+1 :
break;
case '1' :
break;
case true :
break;
case 1.0 :
break;
case $y :
break;
}
24. Deprecated features
Not happening if a parent case has a __constructor()
Not happening if the class is in a namespace
Use the E_DEPRECATED error level while in DEV
Methods with the same name as their
class will not be constructors in a
future version of PHP; foo has a
deprecated constructor
25. php -l with other versions
syntax error, unexpected 'new' (T_NEW)
Assigning the return value of new by reference is
deprecated (PHP 5.6)
PHP 7 -> PHP 5.6
$o =& new Stdclass();
26. Migration to PHP 7
Lint with
PHP 7.0
PHP 7.1 (or src)
PHP 5.6 (current)
PHP 5.5, 5.4,… (manual)
32. Grep on PHP code
1318 reports
doc/_ext/configext.py: parts = text.split("']['")
js/codemirror/lib/codemirror.js: var change = {from: pos, to: pos, text: splitLines
po/zh_CN.po:"example: address can be split into street, city, country an
libraries/Advisor.php: public static function splitJustification($rule)
libraries/plugins/ImportCsv.php: $tmp = preg_split('/,( ?)/', $csv_columns);
libraries/Config.php: // split file to lines
37. PHP7cc
PHP 7 Compatibility Checker
Authored by sstalle
https://github.com/sstalle/php7cc
PHP 5, works with "nikic/php-parser": "~1.4"
Display to stdout
38. 8.506s 3 results 27 analysis
php ~/.composer/vendor/bin/php7cc library/
File: /Users/famille/Desktop/analyze/library/Analyzer/Analyzer.php
> Line 231: Function argument(s) returned by "func_get_args" might have been modified
func_get_args();
File: /Users/famille/Desktop/analyze/library/Analyzer/Functions/MarkCallable.php
> Line 32: Nested by-reference foreach loop, make sure there is no iteration over the same array
foreach ($lists as $id => &$function) {
}
File: /Users/famille/Desktop/analyze/library/Tasks/Analyze.php
> Line 118: Possible adding to array on the last iteration of a by-reference foreach loop
$dependencies[$v] = $dep;
Checked 873 files in 8.506 seconds
39. PHAN
Static analysis for PHP
Inited by Rasmus, under work at Etsy
https://github.com/etsy/phan
PHP 7 only, with ext/ast
php ~/.composer/vendor/bin/phan -f phan.in -3 vendor -o
phan.out
40. 11.244s 333 results
PhanUndeclaredProperty Reference to undeclared property processed
PhanUndeclaredProperty Reference to undeclared property stdclass->results
PhanNonClassMethodCall Call to method relateTo on non-class type null
PhanStaticCallToNonStatic Static call to non-static method loadercypher::saveTokenCounts() defined at library//Loa
PhanAccessPropertyProtected Cannot access protected property tokenizertoken::$alternativeEnding
PhanTypeMismatchArgument Argument 1 (atom) is string but analyzerstructuresuseconstant::atomfunctionis() take
PhanUndeclaredClassMethod Call to method __construct from undeclared class reportsxmlwriter
PhanUndeclaredVariable Variable $r is undeclared
84 analysis
41. Exakat
Static analysis engine for PHP
https://github.com/exakat/exakat
PHP 5.2 to 7.1; Uses Neo4j 2.2 and Gremlin
php exakat.phar project -p name
43. PHP inspections
Static analysis engine for within the IDE
Vladimir Reznichenko
https://bitbucket.org/kalessil/phpinspectionsea
Written in Java
Runs from within PHPstorm
57. Where to look for ?
default_charset
Search for ini_set, ini_get, ini_get_all, ini_restore,
get_cfg_var
Search in php.ini, .htaccess
Search for htmlentities(), html_entity_decode() and
htmlspecialchars()
66. Invalid octals are invalid
<?php
$x = 0890;
Upgraded from silent to Fatal error
PHP Parse error: Invalid numeric literal in test.php
67. More invalid octals in strings
<?php
var_dump("000" === "400");
Coming in PHP 7.1
https://wiki.php.net/rfc/octal.overload-checking
68. More reserved keywords
bool, int, float, string, null, true, false
are no more available for class / interface / traits names
mixed, numeric, object, resource
are reserved for future use
In 7.1, void is also forbidden
69. More relaxed keywords
Almost all PHP keywords are now authorized inside classes
Methods and constants
Except for class, which can't be a class constant name.
<?php
class foo {
const instanceof = 1;
function use() {
$this->while(4) + foo::instanceof;
}
}
70. Strings may be invalid
<?php
echo "u{1F418}n";
Upgraded to Fatal error
> php56 test.php
u{1F418}
> php70 test.php
🐘
<?php
echo "u{52A0}u{6CB9}u{4E2D}u{56FD}n";
//
71. Strings may be invalid
<?php
echo "u{Yes}n";
PHP Parse error:
Invalid UTF-8 codepoint escape sequence
in test.php on line 3
u{
76. Exceptions
Exception is not the top exception type anymore
It is now the 'throwable' interface
Impact on Exception handler
Avoid type hinting until moved to PHP 7
Impact on Error handler
Impact on catch() clauses
78. More catching exceptions
Parser errors now throw a ParseError object. Error
handling for eval()
<?php
try {
$file = new finfo(FILEINFO_NONE,$magic_file);
} catch( ParseError $e) {
log($e->getMessage());
// attempt to fix this or error handling
}
80. Negative string offset (7.1)
<?php
$string = "abcde";
print $string[-3];
print "$string[3]";
print "$string[-2]";
c
d
Parse error: syntax error, unexpec
(T_STRING) or variable (T_VARIABLE
81. list() with keys => (7.1)
Upgraded to Fatal error
<?php
// Assigns to $a, $b and $c to 0, 1, 2
list($a, $b, $c) = $array;
// Assigns to $a, $b and $c to the keys
//"a", "b" and "c", respectively
list("a" => $a, "b" => $b, "c" => $c) = $array;
82. Call-time pass-by-reference
References are in the function signature
Deprecated warnings until PHP 7
Upgraded to Parse error in PHP 7
<?php
$a = 3;
function f($b) {
$b++;
}
f(&$a);
print $a;
?>
PHP Parse error: syntax error, unexpected '&' in …
84. Easy to spot
Strict Standards: Non-static method A::f()
should not be called statically in test.php on
line 6
Deprecated: Non-static method A::f() should
not be called statically in test.php on line 6
90. Automatically fixed
It is not safe to rely on the system's timezone
settings. You are required to use the
date.timezone setting or the
date_default_timezone_set() function. In case
you used any of those methods and you are
still getting this warning, you most likely
misspelled the timezone identifier.
96. Don't hide in parentheses
<?php
function getArray() {
return [1, 2, 3];
}
function squareArray(array &$a) {
foreach ($a as &$v) {
$v **= 2;
}
}
// Generates a warning in PHP 7.
squareArray((getArray()));
?>
Parenthesis in
arguments won't
mask error anymore
97. Constant arrays
Lots of properties should be constants
<?php
class Version {
const SUPPORTED = ['1.0', '1.1', '2.0', '2.1'];
private $an_array = [1,2,3,4];
public function isSupported($x) {
return isset(Version::SUPPORTED[$x]);
}
}
107. Parameters evolution (7.1)
get_headers() has an extra parameter
Passing a custom stream context
getenv() doesn't need parameter
all the current environment variables will be returned
109. Null-coalesce
Shorter way to give a test for NULL and failover
<?php
// PHP 5.6
$x = $_GET['x'] === null ? 'default' : $_GET['x'];
// PHP 7.0
$x = $_GET['x'] ?? 'default';
?>
110. Spaceship operator
Very Cute <=>
Replaces a lot of code
Mainly useful for usort()
<?php
// PHP 5.6
if ($a > $b) {
echo 1;
} elseif ($a < $b) {
echo -1;
} else {
echo 0;
}
// PHP 7.0
echo $a <=> $b; // 0
111. Generators delegation
New yield keyword
Save memory from
n down to 1 value
Good for long or infinite loops
Search for range(), for() or loops
<?php
function factors($limit) {
yield 2;
yield 3;
yield from primeTill1000();
for ($i = 1001; $i <= $limit; $i += 2) {
yield $i;
}
}
$prime = 1357;
foreach (factors(sqrt($prime)) as $n) {
echo "$n ". ($prime % $n ? ' not ' : '') . " factorn";
}
112. Generators
New yield from keyword
Save memory from n down to 1 value
Delegate generators
Great for long, unbounded or infinite loops
Search for range(), for(), foreach() or loops
literals, database result sets, file lines
114. Scalar typehint
Whenever type is tested =>
<?php
function foo($x) {
if (!is_string($x)) {
throw new Exception('Type error while calling ' .
__FUNCTION__);
} ...
}
<?php
function foo(string $x) {
...
}
115. Scalar typehint back in 5.6
Whenever type is tested =>
<?php
function foo(string $x) { }
foo('that');
Catchable fatal error: Argument 1 passed to
foo() must be an instance of string,
string given, called in file..