Preparing for the next PHP version (5.6)

41
Preparing for the next PHP version

description

With versions stretching from 5.3 to 5.6, PHP has several major published versions, that require special attention when migrating. Beyond checking for compilation, the code must be reviewed to avoid pitfalls like obsoletes functions, new features, change in default parameters or behavior. We'll set up a checklist of such traps, and ways to find them in the code and be reading for PHP 5.6.

Transcript of Preparing for the next PHP version (5.6)

Page 1: Preparing for the next PHP version (5.6)

Preparing for the next PHP version

Page 2: Preparing for the next PHP version (5.6)

Towards PHP 5.5 and 5.6

• Changing version is often a big challenge

• Backward incompatibilities

• New features

• How to spot them ?

Page 3: Preparing for the next PHP version (5.6)

Speaker

• Damien Seguy

• CTO at exakat

• Phather of the plush toy elePHPant

• Will talk on automated code audit later

Page 4: Preparing for the next PHP version (5.6)

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 (5.6)
Page 6: Preparing for the next PHP version (5.6)

PHP lint will find

• Short array syntax

• Function subscripting

• break/continue with variables

• Rare other situations

• Code that won’t compile anyway

Page 7: Preparing for the next PHP version (5.6)

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 8: Preparing for the next PHP version (5.6)

What will change?

• Removed features

• Deprecated features

• Changed features

• New features

Page 9: Preparing for the next PHP version (5.6)

Deprecated features• PHP 5.6

• $HTTP_RAW_POST_DATA

• Call From Incompatible Context

• iconv and mbstring directives go to default_charset

• PHP 5.5

• /e in preg_replace

• ext/mysql

• mcrypt arguments

5.6

5.5

Page 10: Preparing for the next PHP version (5.6)

Deprecated features• $HTTP_RAW_POST_DATA

• Replace it by php://input

• php://input is now reusable

• ext/mysql

• Look for mysql_* functions

• Probably in Db/Adapter

5.6

5.5

Page 11: Preparing for the next PHP version (5.6)

Search is your friend

• Grep, or IDE’s search function will help you

• Look for mysql_*

• $HTTP_RAW_POST_DATA

Page 12: Preparing for the next PHP version (5.6)

Deprecated: The mysql extension is deprecated and will be removed in

the future: use mysqli or PDO instead in /path/to/filename.php on

line 11

Error_level to E_STRICT

Page 13: Preparing for the next PHP version (5.6)

/e and charset directives

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

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

• in php.ini, check for mbstring, iconv and default_charset

5.5

5.6

Page 14: Preparing for the next PHP version (5.6)

Where to look for• preg_replace

• Search for preg_replace function calls

• defaut_charset

• Search for ini_set, ini_get, ini_get_all, ini_restore, get_cfg_var

• Seach in php.ini, .htaccess

Page 15: Preparing for the next PHP version (5.6)

Incompatible context

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

$ php53 test.php

Notice: Undefined variable: this in test.php on line 3 A

$ php56 test.php

Strict Standards: Non-static method A::f() should not be called statically in /Users/famille/Desktop/test.php on line 6

Notice: Undefined variable: this in test.php on line 3 A

5.6

Page 16: Preparing for the next PHP version (5.6)

Search for situations• Search for :: operator

• Get the class

• then the method

• then the static keyword

• Needs a automated auditing tool

• Code sniffer, IDE

Page 17: Preparing for the next PHP version (5.6)

Strict Standards: Non-static method A::f() should not be called statically in test.php on line 6

Page 18: Preparing for the next PHP version (5.6)

Changed behavior• json_decode is stricter

• it was more tolerant before with TRUE or False values

• gmp resources are object

• and not resources

• search for is_resource()

• mcrypt requires valid keys and vectors

• check correct size and vector presence

• pack and unpack

• More compatible with Perl

• Z and a format code must be checked

5.6

5.5

Page 19: Preparing for the next PHP version (5.6)

Added structures• PHP adds

• constants

• functions

• extensions

• traits

• interfaces

Page 20: Preparing for the next PHP version (5.6)

Added structuresFunctions Classes Constants

5.3 25 18 80

5.4 0 9 78

5.5 113 9 37

5.6 19 0 24

Total 157 36 219

Page 21: Preparing for the next PHP version (5.6)

New features

• Fixing

• Modernization

• New feature

Page 22: Preparing for the next PHP version (5.6)

Fixing

Page 23: Preparing for the next PHP version (5.6)

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

function myFunction() {     return -2 ; }

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

5.5

Page 24: Preparing for the next PHP version (5.6)

SELF::const != self::const<?php

class object {     const x = 1;          function x() { print SELF::x."\n"; } }

$object = new object(); $object->x(); ?>

Fatal error: Class 'SELF' not found in test.php on line 6

5.5

Page 25: Preparing for the next PHP version (5.6)

Modernization

Page 26: Preparing for the next PHP version (5.6)

Dereferencing

• Direct access to element in a string or an array.

<?php  /// Function dereferencingecho str_split("123", 1 )[2];  echo "\n"; 

/// Array dereferencingecho [5, 5, 3][0];  echo "\n"; 

/// String dereferencingecho 'PHP'[0];  echo "\n";  ?>5.5

Page 27: Preparing for the next PHP version (5.6)

Power operator

• Replaces pow()

• Be aware of precedence

echo pow(2, 3); 

$a=2;  $a **= 3; 

$a = 2 ** 3; 

5.6

Page 28: Preparing for the next PHP version (5.6)

… Variadic

• replaces func_get_args()

• Easier to read

function array_power($pow, ...$integers) {     foreach($integers as $i) {        print "$i ^ $pow  = ". ($i ** $pow)."\n";     }  }     array_power(3, 1, 2, 3, 4, 5); 

1 ^ 3 = 12 ^ 3 = 83 ^ 3 = 274 ^ 3 = 645 ^ 3 = 125

5.6

Page 29: Preparing for the next PHP version (5.6)

Variadic …• replaces

call_user_func_array

• Easier to read

• Works on functions

• Works with typehint

• Doesn’t work with references

function array_power($pow, ...$integers) {     foreach($integers as $i) {        print "$i ^ $pow  = ". ($i ** $pow)."\n";     }  }     array_power(3, ...range(1, 5));  array_power(3, ...[1, 2, 3, 4, 5]);  array_power(3, ...[1, 2, 3], ...[4, 5]); 

1 ^ 3 = 12 ^ 3 = 83 ^ 3 = 274 ^ 3 = 645 ^ 3 = 125

Page 30: Preparing for the next PHP version (5.6)

Generatorsfunction factors($limit) {     $r = array(2);     for ($i = 3; $i <= $limit; $i += 2) {         $r[] = $i;     }     return $r; }

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

• $step big => huge memory usage

5.5

Page 31: Preparing for the next PHP version (5.6)

Generators• New yield keyword

• Save memory from n down to 1 value

• Good for long or infinite loops

• Search for range(), for() or loops

function factors($limit) {     yield 2;     for ($i = 3; $i <= $limit; $i += 2) {         yield $i;     } }

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

Page 32: Preparing for the next PHP version (5.6)

Finallyfunction x() {        $r = new resource();         try {             $result = $r->do();         }         catch (NetworkException $e) {             unset ($r);             throw $e;         }         catch (UnexpectedException $e) {             unset ($r);             throw $e;         }         catch (DaylightSavingException $e) {             unset ($r);             throw $e;         }                  unset ($r);         return $result; }

• Clean up after exception

• What if return in try?

• Move cleaning to __destruct()?

5.5

Page 33: Preparing for the next PHP version (5.6)

Finally

• Clean up after exception or not

• Clean up even when return too early

function x() {        $r = new resource();         try {             $result = $r->do();         }         catch (NetworkException $e) {

       throw $e;}

        catch (UnexpectedException $e) {             throw $e;         }         catch (DaylightSavingException $e) {

// just ignore this one} finally { unset ($r) ;}

                return $result; }

Page 34: Preparing for the next PHP version (5.6)

Really new

Page 35: Preparing for the next PHP version (5.6)

Class name resolution

<?php namespace Name\Space; class ClassName {}

echo ClassName::class;

echo "\n"; ?>

• Get the full name of a class with ::class

5.5

Page 36: Preparing for the next PHP version (5.6)

__debugInfo()class somePasswordSafe {     private $user;     private $password;

    public function __construct($user, $password) {         $this->user = $user;         $this->password = $password;     }

    public function __debugInfo() {         return [             'user' => $this->password,             'password' => '**********',         ];     } }

print_r(new somePasswordSafe('root', 'secret'));

somePasswordSafe Object( [user] => secret [password] => **********)

5.6

Page 37: Preparing for the next PHP version (5.6)

use const / functionsnamespace Name\Space {     const FOO = 42;     function f() { echo __FUNCTION__."\n"; } }

namespace {     use const Name\Space\FOO;     use function Name\Space\f;

    echo FOO."\n";     f(); }

• Importing constants or functions from another namespace

• Keep things separated

• Avoid polluting global namespace

• Avoid static only classes

5.6

Page 38: Preparing for the next PHP version (5.6)

Constant scalar expressionsclass 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;

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

• Code automation

• Won’t accept functioncalls

• Keep it simple5.6

Page 39: Preparing for the next PHP version (5.6)

Foreach supports list• And any type

of keys

• Good with Iterator classes

• Not possible with Arrays

<?php

class object implements Iterator {     /.../     function key() { return array(1,2); }     function current() { return 3; }     /.../ }

$object = new object(); foreach($object as list($a, $b) = $c) {     print "$a + $b + $c = ".($a + $b + $c)."\n"; } ?>

5.5

Page 40: Preparing for the next PHP version (5.6)

Context changes• PHP 5.6

• Windows XP and 2003 dropped

• Support for Zend Optimiser

• PHP 5.5

• phpdbg

• Large File Upload5.5

5.6