Preparing for the next php version

53
MIGRATING TO NEW PHP VERSIONS Washington DC, USA

Transcript of Preparing for the next php version

Page 1: Preparing for the next php version

MIGRATING TO NEW PHP VERSIONS

Washington DC, USA

Page 2: Preparing for the next php version

TOWARDS PHP 70

Changing version is always a big challenge

Backward incompatibilities

New features

How to spot them ?

Page 3: Preparing for the next php version

SPEAKER

Damien Seguy

CTO at exakat

Static code analysis for PHP

Page 4: Preparing for the next php version

PHP LINTING

command line : php -l filename.php

Will only parse the code,

not execution

Will spot compilation problems

Page 5: Preparing for the next php version
Page 6: Preparing for the next php version
Page 7: Preparing for the next php version
Page 8: Preparing for the next php version

PHP -L WILL FIND

Short array syntax

Function subscripting

Code that won’t compile anyway

Page 9: Preparing for the next php version

PHP 7 LINTING

Methods with the same name as their class will not be constructors in a future version of PHP

Cannot use a\b\c\Int as Int because 'Int' is a special class name

Switch statements may only contain one default clause

Redefinition of parameter $%s

syntax error, unexpected 'new' (T_NEW)

Page 10: Preparing for the next php version

WHERE ELSE CODE WILL BREAK?

PHP running has 3 stages

parsed

compiled

executed

Checked with lint

Checked with data and UT

Checked code review

Page 11: Preparing for the next php version

GETTING READY

http://php.net/manual/en/migration70.php

UPGRADING TO PHP 7, Davey Shafik

https://github.com/php/php-src/blob/master/UPGRADING

https://github.com/php/php-src/blob/master/NEWS

get_headers() has an extra parameter in 7.1

Page 12: Preparing for the next php version

WHAT WILL CHANGE?

Incompatible changes

Deprecated changes

Changed features

New features

Page 13: Preparing for the next php version

INCOMPATIBILITIES

Features that were dropped

Features that were added

Page 14: Preparing for the next php version

ADDED STRUCTURES

Functions Classes Constants

5.3 40 2 80

5.4 0 9 78

5.5 12 11 57

5.6 1 10 10

7.0 10 10 41

Total 1293 153 1149

Page 15: Preparing for the next php version

NAME IMPACT

get_resources(), intdiv()

PREG_JIT_STACKLIMIT_ERROR

Error, Date

Page 16: Preparing for the next php version

REMOVED FEATURES

$HTTP_RAW_POST_DATA

Replace it by php://input

php://input is now reusable

Page 17: Preparing for the next php version

REMOVED FEATURES

ext/mysql

Look for mysql_* functions

Probably in Db/Adapter

ext/ereg

ereg, ereg_replace, split, sql_regcase

Page 18: Preparing for the next php version

USORT<?php

$array = array(     'foo',     'bar',     'php' );

usort($array, function($a, $b) {     return 0; } );

print_r($array);

Array ( [0] => php [1] => bar [2] => foo )

Array ( [0] => foo [1] => bar [2] => php )

PHP 5

PHP 7

Page 19: Preparing for the next php version

WHERE TO LOOK FOR ?

Find the name of the structure (function name…)

Grep, or IDE’s search function will help you

$HTTP_RAW_POST_DATA

Look for mysql_*

Look ereg, split, usort

Page 20: Preparing for the next php version

PREG_REPLACE AND /E

preg_replace(‘/ /e’, ‘evaled code’, $haystack)

replaced preg_replace_callback(‘/ /‘, closure, $haystack)

preg_replace_callback_array()

Page 21: Preparing for the next php version

PREG_REPLACE_CALLBACK_ARRAY<?php 

$code = "abbbb";

$spec = 'c';

echo preg_replace_callback_array(     array(         "/a/" => function($matches) {                         return strtoupper($matches[0]);                  },         "/b/" => function($matches) use ($spec) { static $i = 0; $i++;

               return "B$i$spec";         }     ), $code);

AB1cB2cB3cB4c

Page 22: Preparing for the next php version

DEFAULT_CHARSET

iconv.input_encoding

iconv.output_encoding

iconv.internal_encoding

mbstring.http_input

mbstring.http_output

mbstring.internal_encoding

default_charset

Page 23: Preparing for the next php version

DEFAULT_CHARSET

htmlentities()

PHP 5.3 : ISO-8859-1

PHP 5.4 : UTF-8

PHP 5.6 : default_charset (also UTF 8)

Page 24: Preparing for the next php version

WHERE TO LOOK FOR ?

preg_replace

Search for preg_replace function calls

Refine with /e, multiples calls

default_charset

Search for ini_set, ini_get, ini_get_all, ini_restore, get_cfg_var

Seach in php.ini, .htaccess

Search for htmlentities(), html_entity_decode() and htmlspecialchars()

Page 25: Preparing for the next php version

DEPRECATED FEATURES

Methods with the same name as their class will not be constructors in a future version of PHP; foo has a deprecated constructor

Not happening if a parent case has a __constructor()

Not happening if the class is in a namespace

Page 26: Preparing for the next php version

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP;

foo has a deprecated constructor

PHP 4 CONSTRUCTORS

Use the E_DEPRECATED error level while in DEV Check the logs

Page 27: Preparing for the next php version

CALL-TIME PASS-BY-REFERENCE

References are in the function signature

Deprecated warnings until PHP 7

A nice Parse error in PHP 7

<?php  

$a = 3;  

function f($b) {       $b++;   }  

f(&$a);   print $a;   ?>

PHP Parse error: syntax error, unexpected '&' in

Page 28: Preparing for the next php version

WHERE TO LOOK FOR ?

Use error level

Set error_level to maximum

Spot errors in the log

Refine

Great to reduce log size

Page 29: Preparing for the next php version

INCOMPATIBLE CONTEXT

<?php  class A {       function f() { echo get_class($this); }  }  A::f();  ?>

Notice: Undefined variable: this in A

Deprecated: Non-static method A::f() should not be called statically in Notice: Undefined variable: this in A

Page 30: Preparing for the next php version

EASY TO SPOT

Use the E_DEPRECATED or strict while in DEV

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

Page 31: Preparing for the next php version

CHANGED BEHAVIOR

Indirect expressions

Page 32: Preparing for the next php version

SEARCH FOR SITUATIONS

Search for :: operator

Get the class

then the method

then the static keyword

Needs a automated auditing tool

Exakat, Code sniffer, IDE

Page 33: Preparing for the next php version

STATIC ANALYZIS

PHP 5, PHP 7 Psr-4 ClearPHP Performance

Page 34: Preparing for the next php version

SUMMARY

PHP lint is your friend

Search in the code

With Grep

Directly, or indirectly

With the logs

Use static analysis tools

Page 35: Preparing for the next php version

NEW FEATURES

They require willpower

Breaks backward compatibility

FUD

Search for places to apply them like for incompatibilities

Page 36: Preparing for the next php version

NEW FEATURES

Fixing

Modernization

New feature

Page 37: Preparing for the next php version

FIXING

Page 38: Preparing for the next php version

EMPTY() UPGRADE

No need anymore to expressions in a variable for empty()!

Fatal error: Can't use function return value in write context in test.php on line 6

5.5

<?php   function myFunction() {      return -2 ;  } 

if (empty(myFunction() + 2)) {      echo "This means 0!\n";  }  ?>

Page 39: Preparing for the next php version

MODERNIZATION

Page 40: Preparing for the next php version

SPACESHIP OPERATOR

Replaces a lot of code

Mainly useful for usort and co

Very Cute

<?php 

// PHP 5.6 if ($a > $b) {  echo 1; } elseif ($a < $b) {   echo -1; } else {   echo 0; }

// PHP 7.0 echo $a <=> $b; // 0

Page 41: Preparing for the next php version

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';

?>

Page 42: Preparing for the next php version

DIRNAME() SECOND ARG

<?php   $path = '/a/b/c/d/e/f';

// PHP 5.6 $root = dirname(dirname(dirname($x)));

// PHP 7 $root = dirname($path, 3); ?>

Page 43: Preparing for the next php version

… VARIADIC

replaces func_get_args()

Easier to read

<?php 

// PHP 5.5 function array_power($pow) {      $integers = func_get_args();    array_unshift($integers);

   foreach($integers as $i) {         print "$i ^ $pow  = ". pow($i, $pow)."\n";      }   }       // PHP 7.0 function array_power($pow, ...$integers) {      foreach($integers as $i) {         print "$i ^ $pow  = ". ($i ** $pow)."\n";      }   }

5.6

Page 44: Preparing for the next php version

VARIADIC …

<?php 

// Avoid!  foreach($source as $x) {   if (is_array($x))      $final = array_merge($final, $x);   } }

Page 45: Preparing for the next php version

VARIADIC …<?php 

$collection = []; foreach($source as $x) {   if (is_array($x))      $collection[] = $x;   } }

// PHP 5.5 $final = call_user_func_array('array_merge', $collection);     // PHP 7.0 $final = array_merge(...$collection);

Page 46: Preparing for the next php version

REALLY NEW

Page 47: Preparing for the next php version

SCALAR TYPE TYPEHINT

Whenever type is tested

<?php  

function foo(string $x) {    if (!is_string($x)) {      throw new Exception('Type error while calling '.__FUNCTION__);    } }

Page 48: Preparing for the next php version

GENERATORS<?php   function factors($limit) {      yield 2;      yield 3;

    yield from prime_database();

    for ($i = 1001; $i <= $limit; $i += 2) {          yield $i;      }  } 

$prime = 1357;  foreach (factors(sqrt($prime)) as $n) {      echo "$n ". ($prime % $n ? ' not ' : '') . " factor\n";  }

Page 49: Preparing for the next php version

GENERATORS

New yield keyword

Save memory from

n down to 1 value

Good for long or infinite loops

Search for range(), for() or loops

literals, database result sets, file lines

Page 50: Preparing for the next php version

<?php   class Version {      const MAJOR = 2;      const MIDDLE = ONE;      const MINOR = 1;      const FULL = Version::MAJOR.'.'.Version::MIDDLE.'.'.Version::MINOR. '-'.PHP_VERSION;      const SHORT = Version::MAJOR.'.'.Version::MIDDLE;      const COMPACT = Version::MAJOR.Version::MIDDLE.Version::MINOR;      const AN_ARRAY = [1,2,3,4];

    public function f($a = (MAJOR == 2) ? 3 : Version::MINOR ** 3) {          return $a;      }  }

CONSTANT SCALAR EXPRESSIONS

Code automation

Keep it simple

Won’t accept functioncalls

Won't accept variables

Page 51: Preparing for the next php version

CONSTANT SCALAR EXPRESSIONS

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]);     }  }

Page 52: Preparing for the next php version

SUMMARY

Check the manuals

PHP lint is your friend

Search in the code

Use static analysis tools

Page 53: Preparing for the next php version

THANK [email protected]

http://joind.in/talk/view/14770