PHP7新特性

标量类型声明

PHP的标量类型:

  • bool
  • int
  • float
  • string
function addOne(int a) {
    return a + 1;
}


function addA(string a) {
    return a . "A";
}

严格类型声明

<?php
declare(strict_types=1);

返回类型声明

<?php


class A {
    private $name;
    
    function __construct(string $name) {
        $this->name = $name;
    }
    
    /**
     * @return mixed
     */
    public function getName() {
        return $this->name;
    }
}


function getString(): string {
    return "";
}


function getArray(): array { 
    return [];
}


function getInt(): int {
    return 1.2;
}


function getInt2(): int {
    return '123';
}


function getInt3(): int {
    return '123a';
}


function createA(string $name): A {
    return new A($nam

空合并运算符

空合并运算符用两个问号表示: ??,用来检查值是否存在并且不为空,然后返回第一个操作数,否则返回第二个操作数。

$username = $_SERVER['username'] ?? 'not define';
echo $username . PHP_EOL;


$username = isset($_SERVER['username']) ? $_SERVER['username'] : 'not define';
echo $username . PHP_EOL;


$username = $_SERVER['username'] ?? getenv('USER') ?? 'not define';
echo $username . PHP_EOL;

飞船运算符

飞船运算符用<=>表示,用来比较两个表达式,小于时返回-1,等于时返回0,大于时返回1

echo 1 <=> 2 . PHP_EOL; // 1
echo 1 <=> 1 . PHP_EOL; // 0
echo 5 <=> 3 . PHP_EOL; // -1

使用define定义常量数组

<?php


define('NAME', ['A', 'B', 'C', 'D']);




// NAME[] = 'E';


print_r(NAME

解构赋值

可以在list函数中指定key

<?php
$data = [
    ["id" => 1, "name" => 'Tom'],
    ["id" => 2, "name" => 'Fred'],
];


// list() style
list("id" => $id1, "name" => $name1) = $data[0];


// [] style
["id" => $id1, "name" => $name1] = $data[0];


// list() style
foreach ($data as list("id" => $id, "name" => $name)) {
    // logic here with $id and $name
    echo "$name";
}


// [] style
foreach ($data as ["id" => $id, "name" => $name]) {
    echo "$name";
    // logic here with $id and $nam

匿名类

当一个类不需要被记录,或者一个在执行中只会使用一次时可以考虑使用匿名类。

interface Writer {
    public function write(string $message);
}


function http_response(Writer $writer, $body, $headers=[], $version='HTTP/1.1') {
    $writer->write("$version 200 OK\r\n");
    $writer->write("Content-Type: text/html\r\n");
    $writer->write("Content-Length: " . strlen($body) . "\r\n");
    foreach ($headers as $header => $val) {
        $writer->write("$header: $val\r\n");
    }
    
    $writer->write("\r\n");
    $writer->write($body);
}


http_response(new class implements Writer {
    public function write(string $message) {
        echo $message;
    }
}, "something", array(
    'Location' => '/'
));

命名空间分组导入

  • 导入命名空间内的多个类:use App\Module\{Foo, Bar, Baz}
  • 导入命名空间内的多个函数: use function App\Tool\{some_function}
  • 堕入命名空间内的多个常量:use const App\Tool\{A};

Heredoc

PHP7Heredoc有了更灵活的语法,提高了可读性。

  • 允许结束标记缩近
  • 删除结束标记后的新行要求
$templates = array(
    <<<EOF
    sdkf
    skldjfls
    sdfljkl
    sdf
    ksdjfl
    sdfl
    sdfjl
    EOF,
    <<<EOF
    xxxx
    yyyy
    zzzz 
    EOF
);

类常量可见性

class Bar {
    public const A = 1;
    protected const B = 2;
    private const C = 3;
}

支持负字符串偏移量

$name = 'name';


echo $name[-1];
// output e


PHP5迁移到PHP7编写代码需要注意的地方

保持接口兼容:子类重写父类/实现接口的方法要注意参数兼容

<?php


class P {
    public function printMessage($msg, $newline=false) {
        echo $newline ? $msg.PHP_EOL : $msg;
    }
}






class S extends P {
    # 错误的
    public function printMessage($msg, $newline) {
    }
}


class S extends P {
    # 正确的
    public function printMessage($msg, $newline=false) {
        
    }
}




# output


Warning: Declaration of S::printMessage($msg, $newline)
should be compatible with P::printMessage($msg, $newline = false) 
in /root/phpnewfeatures/parent_sub_class_method.php on l

引用传递参数要是一个变量。

<?php


function group_by_key(&$arr, $key) {}
function new_array() {
  return [];
}


$arr = [];
group_by_key($arr, 'key'); # 正确的




group_by_key([], 'key'); # 错误的
group_by_key(new_array(), 'key'); # 错误的




# output


PHP Fatal error:  Only variables can be passed by reference 
in /root/phpnewfeatures/array_parameter_ref.php on li

switch结构中的continue语句会产生一个警告,应该用break

<?php


for ($i = 0; $i < 3; $i++) {
  switch ($i) {
    case 1:
      continue;
    case 2:
      echo 'yes';
      break;
    default:
      break;
  }
}


# output


PHP Warning:  "continue" targeting switch is equivalent to "break".
Did you mean to use "continue 2"? 
in /root/phpnewfeatures/switch_case_no_continue.php on line

当传递参数过少是将抛出异常,在调用用户定义函数时,如果参数过少,在PHP7之前会产生一个警告,在PHP7会抛出异常。

<?php


function addInts($a, $b, $c) {
    return $a + $b + $c;
}




addInts(1,2, 3);
addInts(1,2);


# output php5
PHP Warning:  Missing argument 3 for addInts(), 
called in /root/phpnewfeatures/too_few_args.php on line 9 and 
defined in /root/phpnewfeatures/too_few_args.php on line 3


# output php7
PHP Fatal error:  Uncaught ArgumentCountError: Too few arguments to function addInts(), 2 passed
in /root/phpnewfeatures/too_few_args.php on line 9 and 
exactly 3 expected in /root/phpnewfeatures/too_few_args.p

下面的名称不能作为类、接口和trait的名称

  1. void
  2. iterable
  3. bool
  4. int
  5. string
  6. NULL
  7. TRUE
  8. FALSE
  9. FLOAT

无效字符串数学运算

<?php


'1b' + 2;




PHP Notice:  A non well formed numeric value encountered 
in /root/phpnewfeatures/non_well_formed_numeric_encountered.php on line

计算非可数类型(non-countable)时会发出警告。对非可数类型调用 count()(或 sizeof())函数,会抛出一个 E_WARNING 错误。

<?php


count('');
count(null);
count(false);
count('hello');
count(1);
count(new StdClass);




# output


Warning: count(): Parameter must be an array or an object that implements Counta

object在之前的版本中被声明为软保留字,现在变为了强制保留字,禁止在任何类和接口中使用该名称。

PHP Fatal error:  Cannot use 'object' as class name as it is reserved

不带引号的字符串

  1. 不带引号的字符串是不存在的全局常量,转化成他们自身的字符串。 在PHP7以前,该行为会产生 E_NOTICE,但现在会产生 E_WARNING。在下一个 PHP 主版本中,将抛出 Error 异常。

 

<?php
$b = hello;


echo $b;


#output


PHP Warning:  Use of undefined constant hello - 
assumed 'hello' (this will throw an Error in a future version of PHP)


hello


array(
a =>

引用返回,一个返回引用的函数,不要返回一个表达式,要返回一个变量。

<?php


$config = [];


function &getConfig() {
   $item = 1;
   return $config[0] =& $item; # line 7
}


function &getConfig2() {
   $item = 1;
   $config[0] = $item;


   return  $item;
}


$c1 =& getConfig();
$c2 =& getConfig2();


?>




PHP Notice:  Only variable references should be returned by reference 
in /root/phpnewfeatures/ref_return_value.php on line 7


PHP Stack trace:
PHP   1. {main}() /root/phpnewfeatures/ref_return_value.php:0
PHP   2. getConfig() /root/phpnewfeatures/ref_return_value.php:17


Notice: Only variable references should be returned by reference 
in /root/phpnewfeatures/ref_return_value.php on line 7


Call Stack:
    0.0011     391504   1. {main}() /root/phpnewfeatures/ref_return_value.php:0
    0.0011     391504   2. getConfig() /root/phpnewfeatures/ref_return_valu

json_decode解码为对象时,如果json的键是空会创建一个空的属性名称,而不是_empty__作为属性名称。

<?php


var_dump(json_decode('{"": 1}'));


#php7
class stdClass#1 (1) {
  public $ =>
  int(1)
}


#php5
class stdClass#1 (1) {
  public $_empty_ =>
  int(1)

json_decode,如果JSON的字面量true,false,null不是小写格式,会返回null,并且设置json_last_error

<?php


var_dump(json_decode('{"checked": False}', true));
var_dump(json_last_error());


# php 7


/root/phpnewfeatures/json_decode_uppercase_true.php:3:
NULL
/root/phpnewfeatures/json_decode_uppercase_true.php:4:
int(4)


# php 5


array(1) {
  'checked' =>
  bool(false)
}
int

数字字符串转换遵循科学计数法

  1. 包括(int)强制转换操作和一下函数
    1. intval
    2. settype
    3. decbin
    4. decoct
    5. dechex

 

<?php


echo (int) '123e3';


# php7
123000


# php5
1

字符串不再支持空索引操作符,在PHP7之前会静默的转换为一个数组。

<?php


$str = '';
$str[] = 'x';


# php5
array(1) {
  [0] =>
  string(1) "x"
}


# php7
PHP Fatal error:  Uncaught Error: [] operator not supported for strings 
in /root/phpnewfeatures/string_empty_index.php:5
Stack trace:
#0 {main}
  thrown in /root/phpnewfeatures/string_empty_index.php on line 5


Fatal error: Uncaught Error: [] operator not supported for strings 
in /root/phpnewfeatures/string_empty_index.php on line 5


Error: [] operator not supported for strings 
in /root/phpnewfeatures/string_empty_index.php on line 5


Call Stack:
    0.0007     391296   1. {main}() /root/phpnewfeatures/string_empty_index.ph

MCrypt已过期,mcrypt库在2007年以来未见任何更新,不再建议使用。可以使用OpenSSL或Sodium替代。

list不再能解开string

<?php


$str = 'abcdfg';


list($a, $b, $c) = $str;


var_dump($a, $b, $c);


# php5
string(1) "a"
string(1) "b"
string(1) "c"


# php7


/root/phpnewfeatures/list_string.php:7:
NULL
/root/phpnewfeatures/list_string.php:7:
NULL
/root/phpnewfeatures/list_string.php:7:

十六进制字符串不再被认为是数字

<?php
var_dump("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>


#php5


bool(true)
bool(true)
int(15)
string(2) "oo"


#php7
/root/phpnewfeatures/hexstring.php:3:
bool(false)
/root/phpnewfeatures/hexstring.php:4:
bool(false)
PHP Notice:  A non well formed numeric value encountered in /root/phpnewfeatures/hexstring.php on line 5
PHP Stack trace:
PHP   1. {main}() /root/phpnewfeatures/hexstring.php:0


Notice: A non well formed numeric value encountered in /root/phpnewfeatures/hexstring.php on line 5


Call Stack:
    0.0008     390712   1. {main}() /root/phpnewfeatures/hexstring.php:0


PHP Notice:  A non well formed numeric value encountered in /root/phpnewfeatures/hexstring.php on line 5
PHP Stack trace:
PHP   1. {main}() /root/phpnewfeatures/hexstring.php:0


Notice: A non well formed numeric value encountered in /root/phpnewfeatures/hexstring.php on line 5


Call Stack:
    0.0008     390712   1. {main}() /root/phpnewfeatures/hexstring.php:0


/root/phpnewfeatures/hexstring.php:5:
int(0)
PHP Notice:  A non well formed numeric value encountered in /root/phpnewfeatures/hexstring.php on line 6
PHP Stack trace:
PHP   1. {main}() /root/phpnewfeatures/hexstring.php:0
PHP   2. substr() /root/phpnewfeatures/hexstring.php:6


Notice: A non well formed numeric value encountered in /root/phpnewfeatures/hexstring.php on line 6


Call Stack:
    0.0008     390712   1. {main}() /root/phpnewfeatures/hexstring.php:0
    0.0049     390744   2. substr() /root/phpnewfeatures/hexstring.php:6


/root/phpnewfeatures/hexstring.php:6:
stri