php 7.1 : elegance of our legacy

47
PHP 7.1 ELEGANCE OF OUR LEGACY 010 PHP, Rotterdam, Netherlands, October 2016 [RC4]

Upload: damien-seguy-

Post on 26-Jan-2017

327 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: PHP 7.1 : elegance of our legacy

PHP 7.1ELEGANCE OF OUR LEGACY

010 PHP, Rotterdam, Netherlands, October 2016

[RC4]

Page 2: PHP 7.1 : elegance of our legacy

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

Page 3: PHP 7.1 : elegance of our legacy

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

Page 4: PHP 7.1 : elegance of our legacy

ALS JE BLIJFT

QUESTIONS

Page 5: PHP 7.1 : elegance of our legacy

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/

Page 6: PHP 7.1 : elegance of our legacy

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

Page 7: PHP 7.1 : elegance of our legacy

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

Page 8: PHP 7.1 : elegance of our legacy
Page 9: PHP 7.1 : elegance of our legacy

INCOMPATIBILITIES MODERNIZATIONS

NEW FEATURES

Page 10: PHP 7.1 : elegance of our legacy

INCOMPATIBILITIES

Page 11: PHP 7.1 : elegance of our legacy

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

Page 12: PHP 7.1 : elegance of our legacy

$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

Page 13: PHP 7.1 : elegance of our legacy

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!

Page 14: PHP 7.1 : elegance of our legacy

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.0RAND MT_RAND

PHP 7.0

Page 15: PHP 7.1 : elegance of our legacy

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

Page 16: PHP 7.1 : elegance of our legacy

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

Page 17: PHP 7.1 : elegance of our legacy

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

Page 18: PHP 7.1 : elegance of our legacy

__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

Page 19: PHP 7.1 : elegance of our legacy

MODERNIZATION

Page 20: PHP 7.1 : elegance of our legacy

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

Page 21: PHP 7.1 : elegance of our legacy

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

Page 22: PHP 7.1 : elegance of our legacy

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

Page 23: PHP 7.1 : elegance of our legacy

NULLABLE TYPES AND DEFAULT

<?php function bar(?string $msg = “default”) {     if ($msg!== null) {         echo $msg;     } }

bar("ok") ;       // OKbar(4) ;          // OK, cast to string

bar(null) ;       // OK, displays nothing bar() ;           // OK, display 'default'

bar([1,2,3]) ;    // Not OK?>

Page 24: PHP 7.1 : elegance of our legacy

CATCHING MORE EXCEPTIONS

<?php

try {    attemptSomething(); } catch (RuntimeException $e) {   fixSomething(); } catch (InvalidArgumentException $e) {   fixSomething(); } catch (BadFunctioncallException $e) {   fixSomethingElse(); } 

Page 25: PHP 7.1 : elegance of our legacy

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

Page 26: PHP 7.1 : elegance of our legacy

OCTAL SEQUENCES

• Octal sequences that are beyond \377 are now reported

<?php print "\123\n"; // Prints S print "\523\n"; // Prints S too ?>

Octal escape sequence overflow \523 is greater than \377

Page 27: PHP 7.1 : elegance of our legacy

STRING SEQUENCES REMINDER

• \0, \x, \u{}

<?php   

echo "\123"; echo "\x53"; echo chr(83);

echo "\xe4\xba\xba"; echo "\u{4EBA}";

S

Page 28: PHP 7.1 : elegance of our legacy

ARITHMETIC NOTICE

<?php ‘1’ + 3 === 4;

‘1 elephpant’ + 3 === 4; ?>

Notice: A non well formed numeric string encountered

Page 29: PHP 7.1 : elegance of our legacy

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 notationecho "1.2345e9" + 0; echo (int) "1.2345e9";

?>

Page 30: PHP 7.1 : elegance of our legacy

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

Page 31: PHP 7.1 : elegance of our legacy

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

Page 32: PHP 7.1 : elegance of our legacy

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 } 

Page 33: PHP 7.1 : elegance of our legacy

MB_EREGI?_REPLACE ALSO DROPS /E IN 7.1

<?php   

$code = "abc de";  

echo mb_eregi_replace( ' ',  '"ren";', $code,  'e');

abcrende

Page 34: PHP 7.1 : elegance of our legacy

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

Page 35: PHP 7.1 : elegance of our legacy

NEW FEATURES

Page 36: PHP 7.1 : elegance of our legacy

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

Page 37: PHP 7.1 : elegance of our legacy

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

Page 38: PHP 7.1 : elegance of our legacy

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

Page 39: PHP 7.1 : elegance of our legacy

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

Page 40: PHP 7.1 : elegance of our legacy

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

Page 41: PHP 7.1 : elegance of our legacy

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

Page 42: PHP 7.1 : elegance of our legacy

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 "Signal handler called!\n"; });

echo "Start!\n"; posix_kill(posix_getpid(), SIGTERM); $i = 0; // dummy echo "Done!\n";

?>

Page 43: PHP 7.1 : elegance of our legacy

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

Page 44: PHP 7.1 : elegance of our legacy

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){}}   

?>

Page 45: PHP 7.1 : elegance of our legacy

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

?>

Page 46: PHP 7.1 : elegance of our legacy

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…

Page 47: PHP 7.1 : elegance of our legacy

BEDANKT!@EXAKAT - HTTP://WWW.EXAKAT.IO/

https://legacy.joind.in/talk/view/19421