Preparing for the next php version

Preview:

Citation preview

MIGRATING TO NEW PHP VERSIONS

Washington DC, USA

TOWARDS PHP 70

Changing version is always a big challenge

Backward incompatibilities

New features

How to spot them ?

SPEAKER

Damien Seguy

CTO at exakat

Static code analysis for PHP

PHP LINTING

command line : php -l filename.php

Will only parse the code,

not execution

Will spot compilation problems

PHP -L WILL FIND

Short array syntax

Function subscripting

Code that won’t compile anyway

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)

WHERE ELSE CODE WILL BREAK?

PHP running has 3 stages

parsed

compiled

executed

Checked with lint

Checked with data and UT

Checked code review

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

WHAT WILL CHANGE?

Incompatible changes

Deprecated changes

Changed features

New features

INCOMPATIBILITIES

Features that were dropped

Features that were added

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

NAME IMPACT

get_resources(), intdiv()

PREG_JIT_STACKLIMIT_ERROR

Error, Date

REMOVED FEATURES

$HTTP_RAW_POST_DATA

Replace it by php://input

php://input is now reusable

REMOVED FEATURES

ext/mysql

Look for mysql_* functions

Probably in Db/Adapter

ext/ereg

ereg, ereg_replace, split, sql_regcase

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

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

PREG_REPLACE AND /E

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

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

preg_replace_callback_array()

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

DEFAULT_CHARSET

iconv.input_encoding

iconv.output_encoding

iconv.internal_encoding

mbstring.http_input

mbstring.http_output

mbstring.internal_encoding

default_charset

DEFAULT_CHARSET

htmlentities()

PHP 5.3 : ISO-8859-1

PHP 5.4 : UTF-8

PHP 5.6 : default_charset (also UTF 8)

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()

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

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

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

WHERE TO LOOK FOR ?

Use error level

Set error_level to maximum

Spot errors in the log

Refine

Great to reduce log size

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

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

CHANGED BEHAVIOR

Indirect expressions

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

STATIC ANALYZIS

PHP 5, PHP 7 Psr-4 ClearPHP Performance

SUMMARY

PHP lint is your friend

Search in the code

With Grep

Directly, or indirectly

With the logs

Use static analysis tools

NEW FEATURES

They require willpower

Breaks backward compatibility

FUD

Search for places to apply them like for incompatibilities

NEW FEATURES

Fixing

Modernization

New feature

FIXING

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";  }  ?>

MODERNIZATION

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

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

?>

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); ?>

… 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

VARIADIC …

<?php 

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

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

REALLY NEW

SCALAR TYPE TYPEHINT

Whenever type is tested

<?php  

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

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";  }

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

<?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

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

SUMMARY

Check the manuals

PHP lint is your friend

Search in the code

Use static analysis tools

THANK YOU!damien.seguy@gmail.com

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

Recommended