Everyone must migrate to PHP 7! Take advantage of exceptional performance improvements, cut your hardware use in half and enjoy the best of PHP. This workshop is for everyone that is still eyeing PHP 7 while still using PHP 5, and wants to review their 1 million LOC project before jumping to PHP 7. When migrating, we need to check old code and target only the interesting issues. This session will connect the backward incompatibilities and new features to their actual location in the code, relying on static analysis to quickly process a large code base. Based on our accumulated experience and tools, we'll review the issues, diagnose criticality, select the best fixes and prioritize the tasks. All tools are Open Source, and ready to be integrated into your project lifecycle.
7. Living on the edge
http://php.net/manual/en/migration71.php
Online
UPGRADING TO PHP 7.0
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/
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();
27. Switch statements may only
contain one default clause
<?php
switch($x) {
case '1' :
break;
default :
break;
default :
break;
case '2' :
break;
}
28. 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;
}
29. Deprecated features
Not happening if a parent case has a __construct()
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
36. Grep on PHP code
1318 reports
doc/_ext/configext.py: parts = text.split("']['")
js/codemirror/lib/codemirror.js: var change = {from: pos, to: p
po/zh_CN.po:"example: address can be split into stre
libraries/Advisor.php: public static function splitJu
libraries/plugins/ImportCsv.php: $tmp = preg_split('/,( ?)/', $
libraries/Config.php: // split file to lines
41. 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
42. 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
43. 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
44.
45. 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 libr
PhanAccessPropertyProtected Cannot access protected property tokenizertoken::$alternativeEnding
PhanTypeMismatchArgument Argument 1 (atom) is string but analyzerstructuresuseconstant::atomfunction
PhanUndeclaredClassMethod Call to method __construct from undeclared class reportsxmlwriter
PhanUndeclaredVariable Variable $r is undeclared
84 analysis
46. Exakat
Static analysis engine for PHP
https://github.com/exakat/exakat
PHP 5.2 to 7.2;
php exakat.phar project -p name
49. PHP inspections
Static analysis engine for within the IDE
Vladimir Reznichenko
https://bitbucket.org/kalessil/phpinspectionsea
Written in Java
Runs from within PHPstorm
63. 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()
73. Invalid octals are invalid
Upgraded from silent to Fatal error
PHP Parse error: Invalid numeric literal in test.php
<?php
$x = 0890;
74. More invalid octals in strings
<?php
var_dump("000" === "400");
https://wiki.php.net/rfc/octal.overload-checking
75. 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
void
is reserved in 7.1
82. 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
84. 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
}
93. 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 …
95. 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
96. $this is for classes
<?php
class bar{
function foo($this) {
static $this;
global $this;
foreach ($a as $this) {
try {
$a = "this";
$$a = 42;
} catch (Exception $this) {}
}
unset($this);
}
}
101. 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.
106. 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
107. Constant arrays
Lots of properties could be turned to 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]);
}
}
109. Constant arrays
Lots of properties could be turned to 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]);
}
}
119. Parameters evolution
get_headers() has an extra parameter
Passing a custom stream context
getenv() doesn't need parameter
all the current environment variables will be returned
get_class() doesn't allow null anymore
121. 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';
?>
122. 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
123. 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";
}
125. 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) {
...
}
126. 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..
130. Minimum args in custom
functions is Fatal error
<?php
function foo(?int $a, float $b, float $c) {
return $a + $b + $c;
}
echo foo(2, 1);
Minimum args number Fatal error: Uncaught Error:
Too few arguments to function foo(), 2 passed in
131. Helping at migration
Document the evolutions between two versions
Identify anchors in the code
Link the migration to the actual code
Keywords, syntax, code structures
Suggest fallback, work-around, detection tools