1. 程式人生 > >9. PHP5.3-5.6 新特性

9. PHP5.3-5.6 新特性

1. PHP5.3中的新特性

1.1 支援名稱空間(namespace)

毫無疑問,名稱空間是PHP5.3所帶來的最重要的新特性。

在PHP5.3中,可以用名稱空間防止程式碼的衝突,名稱空間的分隔符為 \ 反斜線。

1.2 通過static關鍵字,實現方法的延遲靜態繫結

在PHP中,我們可以在類中通過self關鍵字或者CLASS來判斷或呼叫當前類。但有一個問題,如果我們是在子類中呼叫,得到的結果將是父類。因為在繼承父類的時候,靜態成員就已經被綁定了。例如:

  <?php    
  class A {    
      public static function who() {    
          echo __CLASS__;    
      }    
      public static function test() {    
          self::who();    
      }    
  }    
  class B extends A {    
      public static function who() {    
           echo __CLASS__;    
      }    
  }    
  B::test();

上面程式碼的輸出結果為:A。這和我們的預期結果不同。

PHP5.3中增加了一個static關鍵字來引用當前類,即實現了延遲靜態繫結:

  <?php    
  class A {    
      public static function who() {    
          echo __CLASS__;    
      }    
      public static function test() {    
          static::who(); // 這裡實現了延遲的靜態繫結    
      }    
  }    
  class B extends A {    
      public static function who() {    
           echo __CLASS__;    
      }    
  }    
  B::test();   
  // 輸出:B

1.3 支援goto語句

多數計算機程式設計語言中都支援無條件轉向語句goto,當程式執行到goto語句時,即轉向由goto語句中的標號指出的程式位置繼續執行。儘管goto語句有可能會導致程式流程不清晰,可讀性減弱,但在某些情況下具有其獨特的方便之處,例如中斷深度巢狀的迴圈和 if 語句。

  <?php
  goto test;
  echo '1';

  test:
  echo '2';
  ?>
  // 執行時會輸出 2

1.4 支援閉包

閉包(Closure)函式和Lambda函式的概念來自於函式程式設計領域。例如JavaScript 是支援閉包和 lambda 函式的最常見語言之一。

在PHP5.3中,可以使用匿名函式或Lambda函式來定義一些臨時使用(即用即棄型)的函式,以作為array_map()或array_walk()等函式的回撥函式。

1.5 新增兩個魔術方法__callStatic()和__invoke()

PHP中原本有一個魔術方法__call(),當呼叫類中某個不存在的方法時該魔術方法會被自動呼叫。新增的__callStatic()方法則只用於類的靜態方法。當嘗試呼叫類中不存在的靜態方法時,__callStatic()魔術方法將被自動呼叫。

此外,PHP5.3中還新增了__invoke()魔術方法。當嘗試以呼叫函式的方式呼叫一個物件時,__invoke() 方法會被自動呼叫。 如:

  <?php
  class CallableClass 
  {
      function __invoke($x) {
          var_dump($x);
      }
  }
  $obj = new CallableClass;
  $obj(5);
  var_dump(is_callable($obj));
  ?> 
  /* 輸出結果:
  int(5)
  bool(true)
  */

1.6 新增Nowdoc語法結構

就象 Heredoc 結構類似於雙引號字串,Nowdoc 結構是類似於單引號字串的。Nowdoc 結構很象 heredoc 結構,但是 nowdoc 中不進行解析操作。故非常適合於傳遞一段PHP程式碼。

  <?php
  $str = <<<'EOD'
  Example of string
  spanning multiple lines
  using nowdoc syntax.
  EOD;
  echo $str;

1.7 const 關鍵字可用來在類外定義常量

  <?php
  //PHP中定義常量通常是用這種方式  
  define("CONSTANT", "Hello world.");  
  //PHP5.3中的const關鍵字也支援在類外定義常量
  const CONSTANT = 'Hello World';  

1.8 三元運算子可以簡寫為省略中間的部分

原本格式為 expr1 ? expr2 : expr3 。

如果expr1結果為True,則返回expr2的結果,否則返回expr3。

PHP5.3新增了一種書寫方式,可以省略中間部分,簡寫為 expr1 ?: expr3 ,當 expr1 為 TRUE 時返回 expr1,否則返回 expr3。

1.9 支援動態訪問類的靜態成員或靜態方法

  <?php
  class Test{    
      public static function testgo()    
      {    
           echo "gogo!";    
      }    
  }    
  $class = 'Test';    
  $action = 'testgo';    
  $class::$action();  //輸出 "gogo!" 

1.10 支援try…catch異常捕獲的巢狀

  <?php
  class MyException extends Exception { }
  class Test {
      public function testing() {
          try {
              try {
                  throw new MyException('foo!');
              } catch (MyException $e) {
                  /* rethrow it */
                  throw $e;
              }
          } catch (Exception $e) {
              return $e->getMessage();
          }
      }
  }
  $foo = new Test;
  echo $foo->testing();
  // 輸出:foo!
  ?>

此外,PHP5.3還棄用了一些老版本的功能和函式,並用新的函式進行替代,這裡不做贅述。

2. PHP5.4中的新特性

2.1 新增traits

Traits提供了一種靈活的程式碼重用機制,既不像interface一樣只能定義方法但不能實現,又不像class一樣只能單繼承。

  <?php
  // Traits不能被單獨例項化,只能被類所包含
  trait SayWorld
  {    public function sayHello()
      {
          echo 'World!';
      }
  }
  class MyHelloWorld
  {
      // 將SayWorld中的成員包含進來
      use SayWorld;
  }
  $xxoo = new MyHelloWorld();
  // sayHello() 函式是來自 SayWorld 構件的
  $xxoo->sayHello();

2.2 新增短陣列語法

  <?php
  // 原來的陣列寫法
  $arr = array("key" => "value", "key2" => "value2");
  $arr = array(1,2,3,4);
  // 簡寫形式
  $arr = ["key" => "value", "key2" => "value2"];
  $arr = [1,2,3,4];

2.3 支援對函式返回陣列的成員訪問解析

  <?php
  function myfunc() {
      return array('jack','rose');
  }
  // 以前的寫法
  $arr = myfunc();
  echo $arr[0];
  // PHP5.4中,支援這樣書寫
  echo myfunc()[0];

2.4 內建了用於開發的 CLI 模式的 web server

  //啟動Web伺服器
  php -S localhost:8000
  //啟動時指定根目錄
  php -S localhost:8000 -t /home/me/public_html/foo
  //使用路由(Router)指令碼
  php -S localhost:8000 index.php //所有的請求都會由index.php來處理。

2.5 支援在例項化時訪問類成員

  (new Foo)->bar();

2.6 session提供了上傳進度支援

通過 $_SESSION[“upload_progress_name”] 就可以獲得當前檔案上傳的進度資訊,結合 Ajax 就能很容易的實現上傳進度條。

2.7 讓Json更懂中文(JSON_UNESCAPED_UNICODE)

PHP5.4中的json_encode()函式的第二個引數,新增了一個常量JSON_UNESCAPED_UNICODE,可有效防止中文字元被轉成Unicode編碼格式。

  <?php
  echo json_encode(array("中文"));
  // 輸出:["\u4e2d\u6587"]
  echo json_encode(array("中文"), JSON_UNESCAPED_UNICODE);
  // 輸出:["中文"]
  // 如果第二個引數指定為JSON_UNESCAPED_UNICODE,就不會將中文轉換為Unicode編碼格式 

2.8 default_charset從ISO-8859-1變為UTF-8

預設傳送“Content-Type: text/html; charset=utf-8”,你再也不需要在HTML裡寫meta 標籤了,也無需為UTF-8相容而傳送額外的header了。

2.9 新增二進位制直接量

  <?php
  $bin = bindec('1101'); //之前需要這樣寫
  $bin = 0b1101;
  echo $bin; // 輸出13

2.10 支援宣告函式的引數型別

  <?php
  function foo(array $arr) {  // 宣告foo函式的引數型別必須是array
      echo json_encode($arr);
  }
  // foo(1);   // 這裡會報錯,foo的引數型別必須是array
  foo(array(1,2,3));  // 正確

此外,PHP5.4 廢除了register_globals、 magic_quotes、 allow_call_time_pass_reference以及安全模式等等。

在早期版本中,你可以在函式呼叫時,在引數前新增&修飾符來指明引數變數按引用傳遞。但在 PHP 5.4 中,該用法已被移除,你只需要在函式宣告時指定按引用傳遞即可。

  <?php
  // 早期版本中,要想給一個函式傳遞一個引用,是這樣寫的
  /* function foo($a) {
      $a = 100;
  }
  $a = 3;
  foo(&$a);
  echo $a; */

  // 自PHP5.4以後,不能再像上面那樣用,如果還想給一個函式傳遞一個引用,可以在宣告時就指明
  function goo(&$a) {
      $a = 100;
  }
  $a = 3;
  goo($a);
  echo $a;  // 輸出:100

3. PHP5.5中的新特性

3.1 新增Generator生成器yield

yield關鍵字用於當函式需要返回一個迭代器的時候,逐個返回值。

複製程式碼

  <?php
  function number10()
  {
      for($i = 1; $i <= 10; $i += 1) {
          yield $i;
      }
  }
  $generatorObj = number10();   // 是一個物件
  // var_dump($generatorObj);
  foreach ($generatorObj as $i) {
      echo $i;
  }
  // 輸出:12345678910

3.2 try…catch 新增了finally

這和java中的finally一樣,經典的try … catch … finally 三段式異常處理。

不論是否捕獲到異常,finally中的程式碼都會執行。只要finally中有return語句,就以finally的返回值為準;否則,以try或者catch中的返回值為準。

  <?php
  function foo() {
      try {
          echo 'success!'.PHP_EOL;
          throw new Exception('exception!');
          echo 'failed!'.PHP_EOL;
          return 1;
      } catch (Exception $e) {
          echo $e->getMessage().PHP_EOL;
          return 2;
      } finally {
          echo "finally!".PHP_EOL;
          return 3;
      }
  }
  echo foo();
  // 輸出:success! exception! finally! 3

3.3 foreach中支援巢狀list()結構

對二維陣列進行遍歷,之前可能需要使用兩個foreach,現在只需要使用foreach + list了,但是需確保個數一致。

  <?php
  $arr = [   
      [1, 2, 3],
      [4, 5, 6]
  ];
  foreach ($arr as list($a, $b, $c)) {
      echo $a.$b.$c.'<br>';
  }
  /* 
  輸出:
  123
  456 
  */

3.4 empty() 支援傳入表示式,而不僅是一個變數

  <?php
  function always_false() {
      return false;
  }
  if (empty(always_false())) {
      echo 'This will be printed.';
  }

3.5 非變數array或string也能支援下標訪問

  <?php
  echo array(1, 2, 3)[0];  
  echo [1, 2, 3][0];  
  echo "foobar"[0];  
  // 輸出:11f

3.6 新增密碼雜湊API

缺點是缺乏互操作性,在需要和其他語言對接時會比較麻煩。

  <?php 
  $passwd = '123456';
  // 加密,將原密碼生成一個hash雜湊值
  $hashKey = password_hash($passwd, PASSWORD_DEFAULT);  // 每次重新整理,生成的hash雜湊值都不一樣
  echo $hashKey,'<br>';
  //輸出結果類似於:$2y$10$Z215AkvS1sFVi4syS9no7eGXCa9mBwiH1BviaQzy4Dh4RvL2/JtpK

  // 驗證,利用hash雜湊值對原密碼進行驗證
  if(password_verify($passwd, $hashKey)) { 
      echo "密碼正確!";
  } else {  
      echo "密碼錯誤!";
  }

3.7 新增 boolval() 函式

PHP已經實現了strval、intval和floatval的函式來進行強制型別轉換。為了達到一致性,PHP5.5新增了boolval函式。

3.8 新增 array_column() 函式

可用來返回二維陣列中指定的列。

  <?php 
  $records = array(
      array('id' => 2135,'name' => 'John'),
      array('id' => 3245,'name' => 'Smith'),
      array('id' => 5342,'name' => 'Peter')
  );

  //從結果集中取出 name 列
  $names = array_column($records, 'name');
  print_r($names);

  //從結果集中取出 name 列,並用相應的 id 作為鍵
  $names = array_column($records, 'name', 'id');
  print_r($names);

4. PHP5.6中的新特性

4.1 增強了const 常量

在PHP5.6之前,關鍵字const定義常量時,只能使用固定的值,且值的型別只能是標量。

在PHP5.6中,對const常量進行了增強,允許常量計算,允許使用包含數字、字串字面值和常量的表示式結果來定義const常量。常量的值也可以為一個數組,但不能是變數。

  <?php const A = 2; const B = A + 1; const C = "Hello"." Wolrd!"; const D = array(1, 2, 3); define('E', 100); var_dump(A, B, C ,D, E); // 輸出:int(2) int(3) string(12) "Hello Wolrd!" array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } int(100) 

4.2 支援使用 … 運算子定義變長引數函式

現在可以不依賴 func_get_args(), 使用 … 運算子來實現變長引數函式。

  <?php
  function test(...$args)
  {
      var_dump($args);
  }
  test(1,2,3);
  // 輸出:array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } 

4.3 支援使用 ** 進行冪運算

加入右連線運算子 * 來進行冪運算。 同時還支援簡寫的 *= 運算子,表示進行冪運算並賦值。

  <?php
  printf(2 ** 3); // 8
  $a = 2;
  $a **= 3;
  printf($a);  // 8

4.4 名稱空間 use 操作符支援函式和常量的匯入

use 運算子可以匯入外部(其他名稱空間)的函式和常量,對應的結構為 use function 和 use const。

  <?php
  namespace Name\Space {  
      const FOO = 42;  
      function f() { return __FUNCTION__; }  
  }  

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

      echo '常量:'.FOO;  
      echo '<br>';
      echo '函式:'.f();  
  } 
  /*
  輸出:
  常量:42
  函式:Name\Space\f
  */

4.5 新增引數解包功能

在呼叫函式的時候,通過 … 操作符可以把陣列或者可遍歷物件解包到引數列表,這和Ruby等語言中的擴張(splat)操作符類似。

  <?php
  function add($a, $b, $c) {  
      return $a + $b + $c;  
  }  
  $arr = [2, 3];  
  echo add(1, ...$arr);  // 輸出:6

  4.6 支援大檔案上傳
  可以上傳超過2G的大檔案。

  4.7 php://input 可以被複用
  php://input 是個可以訪問請求的原始資料的只讀流。 在 PHP 5.6 之前 php://input 開啟的資料流只能讀取一次; 資料流不支援 seek 操作。 不過,現在依賴於 SAPI 的實現,請求體資料被儲存的時候, 它可以開啟另一個 php://input 資料流並重新讀取。 通常情況下,這種情況只是針對 POST 請求,而不是其他請求方式。