PHP 7.1
ELEGANCE OF OUR LEGACY
010 PHP, Rotterdam, Netherlands, October 2016
[RC4]
AGENDA
• PHP 7.0 is already on the way out
• PHP 7.1
• RC4 at the moment, so 2 more weeks to wait
• What's new in this version
• What is incompatible with the previous version
• How to do migration
SPEAKER
• Damien Seguy
• Exakat CTO
• Ik ben een boterham
• Static analysis of PHP code
• Get a full report of
compliance for your code
with the exakat engine
ALS JE BLIJFT
QUESTIONS
DONEC QUIS NUNC
LIVING ON THE BLEEDING EDGE
http://php.net/manual/en/migration71.php
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/
QUAM UT PRÆPARATE PRO AGENTIBUS
HOW TO PREPARE FOR MIGRATION
• Code knowledge
• lint
• Grep / Search
• Static analysis
• Logs / error_reporting
• You know your code
• php -l on every file
• Fast, universal, false positives
• Exakat, phan
• Run the tests, check logs
QUAM UT PRÆPARATE PRO AGENTIBUS
HOW TO PREPARE FOR MIGRATION
• Code knowledge
• lint
• Grep / Search
• Static analysis
• Logs / error_reporting
• You know your code
• php -l on every file
• Fast, universal, false positives
• Exakat, phan
• Run the tests, check logs
INCOMPATIBILITIES
MODERNIZATIONS
NEW FEATURES
INCOMPATIBILITIES
MCRYPT IS DEPRECATED
• "libmcrypt is a dead project, unmaintained for ~8 years, last
version 2.5.8 was released in February 2007!"
• It emits a E_DEPRECATED notice
• Switch to OpenSSL for serious cryptography
• phpseclib (http://phpseclib.sourceforge.net/)
$THIS IS NOT A WARNING ANYMORE
<?php
function foo($this) { /**/ }
// Fatal error: Cannot use $this as parameter
?>
• Parameter
• Static variable
• Global variable
• Foreach variable
• Catch'ed variable
• Variable variable
• Reference
• Result of extract() or parse_str
RAND() IS NOW AN ALIAS OF MT_RAND()
• RAND() is on its way out
• Since PHP 7.0, use random_int() and random_bytes()
• They provide CSPRN
• Throws exception if it can't
• RAND() is replaced by mt_rand(), better random
• In case the order of the serie is important, beware!
RAND() TO MT_RAND() TO MT_RAND() *
<?php
  srand(10);
  print rand()."n";
  print rand()."n";
  print rand()."n";
?>
1215069295
1311962008
1086128678
1656398468
641584702
44564466
502355954
641584702
2112621188
  mt_srand(10, MT_RAND_PHP);
PHP 7.1
PHP 7.1
PHP 7.0
RAND MT_RAND
PHP 7.0
MISSING ARG IS EXCEPTION
<?php
function test($param){}
test();
PHP Warning: Missing argument 1 for test()
Fatal error: Uncaught ArgumentCountError: Too few
arguments to function test(), 0 passed
PHP 7.0
PHP 7.1
CAN'T BE CALLED DYNAMICALLY ANYMORE
• extract()
• compact()
• get_defined_vars()
• func_get_args()
• func_get_arg()
• func_num_args()
• parse_str() with one argument
• mb_parse_str() with one argument
• assert() with a string argument
Creates too many variables, 

in too many different ways
<?php
namespace {
    function test($a, $b, $c) {
        var_dump(call_user_func('func_num_args'));
    }
    test(1, 2, 3);
}
 
namespace Foo {
    function test($a, $b, $c) {
        var_dump(call_user_func('func_num_args'));
    }
    test(1, 2, 3);
}
?>
PHP 7.0 : int(3)
PHP 7.1 : int(1)
PHP 7.0 : int(1)
PHP 7.1 : int(1)
__DESTRUCTOR ONLY WHEN OBJECT IS COMPLETE
<?php
function throwme($arg) {
   throw new Exception;
}
try {
  $bar = new foo;
} catch(Exception $exc) {
  echo "Caught exception!n";
}
?>
Inside constructor
Caught exception!
Inside constructor
Inside destructor
Caught exception!
https://bugs.php.net/bug.php?id=29368
MODERNIZATION
VOID TYPE
• New pseudo-type for functions that don't return a value
• Not for type hint
<?php
function fooEmpty ($arg) : void {
    return ;
}
function foo ($arg) : void {
}
function fooWithNull ($arg) : void {
    return NULL; // not OK : explicit
}
?>
ITERABLE TYPE
<?php 
function bar($option): iterable { 
   if ($option == 'array') {
     return [1, 2, 3]; 
  } else {
     return new ArrayAccessClass([1,2,3]);
  }
} 
?>
• New pseudo-type that represents arrays and ArrayAccess
• Both may be given to a foreach() loop
• This doesn't work on Closure nor Generators
NULLABLE TYPES
<?php
function foo(): ?int  {
    return null; //ok
    return 3;    //ok
    return "3";  //ok, no strict
    return "no"; //never OK
}
function bar(): ?void  { }
 
?>
• Accepts ? before the type hint
• This means that null is accepted
Fatal error: Void type cannot be nullable
NULLABLE TYPES AND DEFAULT
<?php
function bar(?string $msg = “default”) {
    if ($msg!== null) {
        echo $msg;
    }
}
bar("ok") ;       // OK
bar(4) ;          // OK, cast to string
bar(null) ;       // OK, displays nothing
bar() ;           // OK, display 'default'
bar([1,2,3]) ;    // Not OK
?>
CATCHING MORE EXCEPTIONS
<?php
try {
   attemptSomething();
} catch (RuntimeException $e) {
  fixSomething();
} catch (InvalidArgumentException $e) {
  fixSomething();
} catch (BadFunctioncallException $e) {
  fixSomethingElse();
} 
EVEN MORE CATCHING EXCEPTIONS
Federate error catching in catch clause
Only for Catch
no Type Hint, no Return Type Hint, no instanceof
<?php
try {
   attemptSomething();
} catch (RuntimeException| 
InvalidArgumentException $e) {
  fixSomething();
} catch (BadFunctioncallException $e) {
  fixSomethingElse();
} 
OCTAL SEQUENCES
• Octal sequences that are beyond 377 are now reported
<?php
print "123n"; // Prints S
print "523n"; // Prints S too
?>
Octal escape sequence overflow 523 is greater than 377
STRING SEQUENCES REMINDER
• 0, x, u{}
<?php   
echo "123";
echo "x53";
echo chr(83);
echo "xe4xbaxba";
echo "u{4EBA}";
S
ARITHMETIC NOTICE
<?php
‘1’ + 3 === 4;
‘1 elephpant’ + 3 === 4;
?>
Notice: A non well formed numeric string encountered
ARITHMETIC NOTICE
<?php
$a = "12.00 $CAD" + 1;
$b = "1 023,45" + 2;
$c = "  234  " + 4;
// Don't filter with + 0 !
$amount = abs($_GET['amount']) + 0 ; 
// Unless it is scientific notation
echo "1.2345e9" + 0;
echo (int) "1.2345e9";
?>
SESSION ID SIZE
• Session ID are not hashed anymore
• Speed bump!
• Session ID size is now session.sid_length. sid_length is CSPRN
• 22 to 256 chars; 32 as default; 48 recommended.
• session.sid_bits_per_character specifies 4/5/6 bits characters : 

(hexa, [0-9a-v], [0-9a-zA-Z-,])
• Recommended settings : 48 / 5
• Beware about your filters and storages
SESSION ID ERRORS ARE CATCHABLE
<?php
try{
  session_regenerate_id ();
} catch (Error $e) {
// Log error
// deal with missing session ID
}
?>
• When generated ID are not strings, an Error is emitted
• Catch them to be safe
CSPRN THROW ERRORS
<?php 
try { 
  $random = random_bytes(10);  
} catch( TypeError $e) { 
  // invalid parameter
} catch( Error $e) { 
  // invalid length
} catch( Exception $e) { 
  // no source of randomness
} 
MB_EREGI?_REPLACE ALSO DROPS /E IN 7.1
<?php   
$code = "abc de";  
echo mb_eregi_replace( ' ', 
'"ren";',
$code, 
'e');
abcrende
FUNCTIONS CHANGES
• getenv(), without argument : === $_ENV
• parse_url() now checks that user and pass have no @ chars.
• ext/filter has now FILTER_FLAG_EMAIL_UNICODE, to filter
unicode email, like üser@[IPv6:2001:db8:1ff::a0b:dbd0]
• imap now checks that email is not larger than 16385 bytes
• pg_last_notice() gets 3 constants : 

PGSQL_NOTICE_LAST, PGSQL_NOTICE_ALL, and
PGSQL_NOTICE_CLEAR
NEW FEATURES
LIST() WITH KEYS
<?php
// PHP 7.0 
$array = [0 => 'a', 1 => 'b', 2 => 'c'] ;
list($a, $b, $c) = $array ;
// $a is 'a', $b is 'b', $c is 'c'
?>
LIST() WITH KEYS
<?php
// PHP 7.1
$array = [0 => 'a', 1 => 'b', 2 => 'c'] ;
list(1 => $b, 2 => $c, 0 => $a) = $array ;
// $a is 'a', $b is 'b', $c is 'c'
?>
LIST() WITH KEYS
<?php
class foo {
    private $a, $b = [1]; 
private static $c;
 
    public function __construct(array $bar) {
        list(
            "a" => $this->a,
            "b" => $this->b[],
            "c" => static::$c
        ) = $bar;
    }
}
?>
LIST() WITHOUT LIST
<?php
class foo {
    private $a, $b = [1]; 
private static $c;
 
    public function __construct(array $bar) {
        [
            "a" => $this->a,
            "b" => $this->b[],
            "c" => static::$c
        ] = $bar;
    }
}
?>
NEW TRICKS WITH LIST
<?php
$points = [
    ["x" => 1, "y" => 2],
    ["x" => 2, "y" => 1]
];
 
list(list("x" => $x1, "y" => $y1), 
list("x" => $x2, "y" => $y2)) = $points;
// repeated usage
[ 4 => $a, 4 => $b, 4 => $c] = [ 4 => 5, 6 => 7];
// $a, $b and $c, all, contain 5 
$a = $b = $c = [ 4 => 5, 6 => 7][4];
?>
NEGATIVE OFFSET FOR STRINGS
<?php
    echo substr("abcde", 1, 1) ;  // display b
    echo substr("abcde", -1, 1) ; // display d
    echo "abcde"[1]; // display b
    echo "abcde"[-1]; // display d
    echo "$a[-1]";  // Fatal error
    echo "{$a[-1]}";  // display d
?>
NEW FUNCTIONS
• mb_ord() and mb_chr() : multi-byte version of ord/chr
• mb_scrub() : cleans a string of gremlins
• curl_share_strerror(), curl_multi_errno() and curl_share_errno() : 

access to various kind of errors
• pcntl_async_signals() for

asynchronous signal 

handling, with 

pcntl_signal()
<?php
pcntl_async_signals(1);
pcntl_signal(SIGTERM, function ($signo
echo "Start!n";
posix_kill(posix_getpid(), SIGTERM);
$i = 0; // dummy
echo "Done!n";
CLASS CONSTANT VISIBILITY
• Constants may only be used inside the class or its children
• Interfaces' constants are still public only
• trait's constants are still science-fiction
<?php
class Foo {
    // PHP 7.0 behavior. Nothing changes.
        const PUBLIC_CONST = 0;
 
    // Explicit visibilities
        private const PRIVATE_CONST  = 1;
        protected const PROTECTED_CONST = 2;
        public const PUBLIC_CONST_TWO  = 3, 

PUBLIC_CONST_THREE = 4;
}
?>
CLOSURE::FROMCALLABE()
<?php 
$validator = new Validator(); 
// so PHP 4! 
$callback = array($validator, 'emailValidation'); 
// private methods!
class Validator {   
    private function emailValidation($userData)  {}
    private function genericValidation($userData){}
}   
?>
CLOSURE::FROMCALLABLE()
<?php 
class Validator {   
   public function getValidatorCallback($validationType) {   
      if ($validationType == 'email') { 
         return Closure::fromCallable(

[$this, 'emailValidation']); 
      }   
      return Closure::fromCallable(

[$this, 'genericValidation']); 
   }   
}   
$validator = new Validator(); 
$callback = $validator->getValidatorCallback('email');
$callback($userData);
?>
DONEC QUIS NUNC
TEST PHP 7.1 NOW
• https://github.com/php/php-src
• RC4 : compile, run unit tests, fix your bugs or report PHP's
• Test online : https://3v4l.org/
• Compile your current code with it
• Use static analysis
• Watch out for PHP.Next : PHP 7.2 or PHP 8.0
• Exit with PEAR and PECL, in with composer/Pickle
• Class Friendship, __autoload() deprecations, Automatic SQL injection
protection, INI get/set aliases…
BEDANKT!
@EXAKAT - HTTP://WWW.EXAKAT.IO/
https://legacy.joind.in/talk/view/19421

PHP 7.1 : elegance of our legacy