天天看點

PHP5.4最新特性 17. Zend Signal in PHP 5.4

官網:ChangeLog-5.php#5.4.0

原文Oracle:LAMP 體系有了新的競争,但此版本中的特性使 PHP 再次挑戰極限。稍微做了修改。:

概述總結:

1. 記憶體和性能改進:大型 PHP 應用程式中可節省 20-50% 的記憶體。通過各種優化使性能提高 10-30%

2. 支援特性Trait

3. 精簡數組文法,可以定義短數組

4. 函數數組解除引用,支援Array dereferencing,

5. 執行個體方法調用

6. 閉包綁定

7. 對象即函數

8. 内置 Web 伺服器 (CLI)

9. 原生會話處理程式接口

10. JsonSerializable 接口

11. 二進制表示法

12. 改進了錯誤消息

13. 數組到字元串轉換通知

14. 函數類型提示的增強,(Callable typehint)

15. 對時間統計的增強,高精度計時器

16. 上傳進度條Upload progress

17. Zend Signal in PHP 5.4

18. PHP 5.4 由Arnaud 引入了一個對三元式的優化方案.

1)棄用: allow_call_time_pass_reference、define_syslog_variables、highlight.bg、register_globals、register_long_arrays、magic_quotes、safe_mode、zend.ze1_compatibility_mode、session.bug_compat42、session.bug_compat_warn 以及 y2k_compliance。

2)不再支援PHP 中的 break 和continue 後帶變量文法

3)mysqlnd 這一捆綁的 MySQL 原生驅動程式庫現在預設用于與 MySQL 通信的各種擴充,除非在編譯時通過 ./configure 被顯式覆寫。

大約八年前,我為 Oracle 技術網寫了一篇名為“您了解 PHP 嗎?”的文章。在那篇文章中,我談到了 PHP 固執的功能優于形式的“Web 問題”解決方法,以及它所具備的讓事情變得簡單的能力。當時,我們即将釋出 PHP 5.0。現在,時隔将近十年之後我們推出全新的 PHP 5.4.0 版本,雖然在這期間發生了很多事情,但也有許多事情根本沒變。

沒變的一件事情就是生态系統一如以往那樣重要。解決 Web 問題不僅僅關乎腳本語言的選擇,它關乎的是周圍的整個生态系統。現在,LAMP 體系已盛行近 15 年,仍廣受歡迎,但我們開始注意到其他功能強大的方案。附帶 nginx 的 PHP-FPM 已經快速流行起來,因為從 PHP 5.3 開始大大改進了支援,并在 5.4 中進一步得到簡化。體系中的 M(即資料庫)部分與 8 年前相比也開始變得極為不同。與将所有内容都隻放入 MyISAM 表中相比,各種 NoSQL 解決方案和 MySQL Cluster 提供了一組更豐富的選擇。

出現了多種有趣的技術,因而我們編寫了 PHP 擴充來輕松通路這些技術。我最喜愛的一個擴充是libevent,可以用它在 PHP 中編寫事件驅動的高性能應用程式。另一個是ZeroMQ,這是一個進階套接字庫。與 SQLite 不再需要編寫另一種原始檔案格式和關聯的分析器極為相似,ZeroMQ 也無需因任何理由而使用套接字協定和關聯的套接字處理代碼。您甚至可以組合使用 libevent 和 ZeroMQ,以獲得獨立、高性能、事件驅動的卓越伺服器。(如果您對此感興趣,請參見此示例。)我還十分喜歡SVM(支援向量機)這一機器學習算法,您不必成為機器學習的愛好者也可提出許多問題。

還有許多擴充在最近幾年内已被廣泛接受。特别是,Gearman 變得流行起來,逐漸成為使用者部署的常見體系的一部分。您可以通過 Gearman 分派作業,以便由工作器異步完成這些作業。工作器可以遍布多台伺服器,它們甚至可以進一步分派更多的 MapReduce 類型作業。

2004 年釋出 PHP 5.0 之後,接下來在 2005 年推出 5.1,此版本新增了 DateTime 實作、PDO 和性能改進。PHP 5.2 于 2006 年釋出,引入了改進的記憶體管理器、JSON 支援和輸入篩選。當時,我們着手推動 PHP 6,這是一個極其宏偉的計劃,完全重寫有關 ICU(Unicode 國際化元件)庫的所有内容。事實證明這個計劃有些操之過急 — 我們無法使足夠多的開發人員為之興奮,最終隻得将準備引入 PHP 6 的各種特性添加到 2009 年釋出的 PHP 5.3 中。5.2 與 5.3 版本時隔 3 年,這也意味着 5.3 向 PHP 新增了大量内容:命名空間、後期靜态綁定、閉包、垃圾收集、受限 goto、mysqlnd(MySQL 原生驅動程式)、更好的 Windows 性能以及許多其他内容。

事後看來,将此版本稱為 PHP 6 可能有一定的道理,但 PHP 6 等同于在 Unicode 方面所做的努力,以至于為此編寫了相關書籍,是以我們認為如果沒有對 Unicode 做出重大改進,就不能釋出 PHP 6。我們引入了名為“intl”的 ICU 擴充,它也針對 PHP 5.2 編譯,這可讓您通路更多的 ICU 功能。mbstring 擴充随時間不斷地改進,這意味着幾乎任何與 Unicode 相關的問題都有解決方案,隻是未明确內建到語言本身中。

這樣在 2012 年推出 PHP 5.4。而且,與上一版本時隔将近 3 年,我們在此期間對一些内容進行了改進。我甯願恢複到每年推出一個版本,每個版本包含更少的新特性。

以下是您更新到 5.4 時将看到的主要特性:

1. 記憶體和性能改進

許多内部結構已變得更小或完全消失,進而在大型 PHP 應用程式中可節省 20-50% 的記憶體。通過各種優化使性能提高 10-30%(主要取決于代碼執行的操作),這些優化包括内聯各種常見代碼路徑、将 $GLOBALS 添加到 JIT、“@”操作符運算更快、添加了運作時類/函數/常量緩存、運作時字元串常量現在被拘留、通過預先計算的散列更快地通路常量、空數組速度更快并使用更少記憶體、unserialize() 和 FastCGI 請求處理速度更快,以及在整個代碼中進行更多的記憶體和性能調整。

例如,早期的一些測試表明,Zend Framework 在 5.4 中運作速度提高 21% 并且記憶體使用減少 23%,而 Drupal 記憶體使用減少 50% 并且運作速度大約提高 7%。

2. 支援特性Trait

Trait 可能是 PHP 5.4 中談論最多的特性 — 将它們視為編譯器輔助的複制粘貼。Trait 也是 Scala 的一個特性。其他語言可能将它們稱為“mixin”— 或者這些語言根本不對它們進行命名,但具有擴充接口機制,允許接口包含其方法的實際實作。

與 mixin 相反,PHP 中的 trait 包括顯式沖突解決機制,用于多個 trait 實作相同方法的情況。

trait Singleton {
    public static function getInstance() { ... }
}

class A {
    use Singleton;
    // ...
}

class B extends ArrayObject {
    use Singleton;
    // ...
}

// Singleton method is now available for both classes
A::getInstance();
B::getInstance(); 
           

請參見php.net/traits了解更多示例,包括沖突解決文法、方法優先順序、可見性以及對 trait 中常量和屬性的支援。此外,要詳細了解概念理論,您可以閱讀 Nathan Schärli 的論文“Trait:行為建構塊中的組合類”。

3. 精簡數組文法

新增的一種簡單但非常流行的文法:

$a = [1, 2, 3];
$b = ['foo' => 'orange', 'bar' => 'apple']; 
           

就是說,您現在不再需要使用“array”關鍵字來定義數組。

4. 函數數組解除引用,支援Array dereferencing,

1)新增的另一種常用文法。傳回數組的函數調用現在可以直接解除引用:

function fruits() {
    return ['apple', 'banana', 'orange'];
}
echo fruits()[0]; // Outputs: apple
           

2)有了Array dereferencing, 以前的這種寫法就再也不必要了:

<?php

list($name,) = explode(",", "Laruence, male");

?>

取而代之的是:

$name = explode(",", "b, x")[0];

另外, Array derefencing也可以出現再指派語句的左值中, 也就是理論上你可以這麼寫:

explode(",", "test1, test2")[3] = "phper";

5. 執行個體方法調用

與函數數組解除引用相關,您現在可以調用對象執行個體化方法。與早期版本一樣,您當然仍可以連結方法調用,是以您現在可以編寫如下代碼:

class foo {
    public $x = 1;
 
    public function getX() {
        return $this->x;
    }
    public function setX($val) {
        $this->x = $val;
        return $this;
    }
}
 
$X = (new foo)->setX(20)->getX();
echo $X; // 20 
           

然而,由于可能丢棄執行個體化的對象,是以,除非您的構造函數執行有用操作,否則您應該在此改用靜态方法調用。如果将它與精簡數組文法和函數數組解除引用結合使用,我們可以編寫某些十分複雜的代碼:

class foo extends ArrayObject {
    public function __construct($arr) {
        parent::__construct($arr);
    }
}
 
echo (new foo( [1, [4, 5], 3] ))[1][0]; 
           

看一眼之後,您可以斷定輸出是什麼嗎?在此,我們将二維數組傳遞到僅傳回數組的構造函數。然後,我們選出第二個次元的第一個元素,是以這将輸出“4”。

6. 閉包綁定

在類執行個體中通過$this引用一個匿名函數(也叫閉包函數)

閉包是在 PHP 5.3 中引入的,但在 5.4 中我們改進了閉包與對象的互動方式。例如:

class Foo {
  private $prop;
  function __construct($prop) {
    $this->prop = $prop;
  }
  public function getPrinter() {
    return function() { echo ucfirst($this->prop); };
  }
}

$a = new Foo('bar');;
$func = $a->getPrinter();
$func(); // Outputs: Bar 
           

注意閉包通路 $this->prop 這一私有屬性。預設情況下,PHP 中的閉包使用預綁定 — 這意味着閉包内的變量具有定義閉包時所具有的值。可以使用引用将其轉換為後綁定。但是,也可以重新綁定閉包:

$a = new Foo('bar');
$b = new Foo('pickle');
$func = $a->getPrinter();
$func(); // Outputs: Bar
$func = $func->bindTo($b);
$func(); // Outputs: Pickle 
           

在此,我們将閉包從 $a 執行個體重新綁定到 $b 中的執行個體。如果您不希望閉包随時通路對象執行個體,可以将閉包聲明為靜态:

class Foo {
  private $prop;
  function __construct($prop) {
    $this->prop = $prop;
  }
  public function getPrinter() {
    return static function() { echo ucfirst($this->prop); };
  }
}

$a = new Foo('bar');;
$func = $a->getPrinter();
$func(); // Fatal error: Using $this when not in object context
           

7. 對象即函數

有一種新的神奇方法,名為“__invoke”,其用法如下:

class MoneyObject {
    private $value;
    function __construct($val) {
        $this->value = $val;
    }
    function __invoke() {
        return sprintf('$%.2f',$this->value);
    }
}
$Money = new MoneyObject(11.02/5*13);
echo $Money(); // Outputs: $28.65
           

8. 内置 Web 伺服器 (CLI)

CLI 伺服器是一種小型 Web 伺服器實作,可以從指令行運作:

% php -S localhost:8000

PHP 5.4.0 Development Server started at Sun Mar 11 13:27:09 2012

Listening on localhost:8080

Document root is /home/rasmus

Press Ctrl-C to quit.
           

CLI 伺服器不适合用作生産 Web 伺服器;我們将使用它運作一些 PHP 回歸測試,其他單元測試機制也可使用它,并且 IDE 也可能使用它。它确實具有一些很有用的特性,用于從指令行進行日常代碼調試。預設情況下,它使用目前目錄作為 DocumentRoot;它也處理靜态檔案請求。預設目錄索引檔案為“index.php”,是以您可以在滿含 .php、.css、.jpg 等檔案的目錄中激活它,它自己就可以運作。對于可能使用 mod_rewrite 将所有請求發送到前端控制器或路由器的更複雜應用程式,您可以将此路由器與一個簡單的小腳本包裝在一起,并啟動 CLI 伺服器,如下所示:

% php -S localhost:8080 /path/to/router.php

PHP 5.4.0 Development Server started at Sun Mar 11 13:28:01 2012

Listening on localhost:8080

Document root is /tmp/web

Press Ctrl-C to quit.
           

router.php 腳本可能如下所示:

<?php
if (preg_match('!\.php$!', $_SERVER["REQUEST_URI"])) {
    require basename($_SERVER["REQUEST_URI"]);
} else if (strpos($_SERVER["REQUEST_URI"], '.')) {
    return false; // serve the requested file as-is.
} else {
    Framework::Router($_SERVER["REQUEST_URI"]);
} 
           

此包裝器加載直接 .php 請求,将包含“.”的任何其他請求傳遞到靜态檔案處理程式,其他所有内容都傳遞到架構的路由器。您可以如此直接從指令行運作 Drupal 和 Symphony。

9. 原生會話處理程式接口

這是一個小而友善的特性,現在可以用它實作會話處理程式接口。現在,您可以僅将會話處理對象的執行個體傳遞給 session_set_save_handler(),而不必傳遞給它六個比較麻煩的函數:

SessionHandler implements SessionHandlerInterface {
  public int close ( void )
  public int destroy ( string $sessionid )
  public int gc ( int $maxlifetime )
  public int open ( string $save_path , string $sessionid )
  public string read ( string $sessionid )
  public int write ( string $sessionid , string $sessiondata )
}
session_set_save_handler(new MySessionHandler); 
           

10. JsonSerializable 接口

現在,您可以通過實作 JsonSerializable 接口來控制有人嘗試使用 json_encode() 對您的對象進行編碼時所發生的情況:

class Foo implements JsonSerializable {
    private $data = 'Bar';
    public function jsonSerialize() {
        return array('data'=>$this->data);
    }
}
echo json_encode(new Foo); // Outputs: {"data":"Bar"}
           

11. 二進制表示法

為了與 PHP 的原生十六進制和八進制支援協調一緻,現在也支援二進制表示法:采用“0b”字首辨別二進制數

$mask=0b010101;

12. 改進了錯誤消息

錯誤消息稍有改進。

改進前:

% php -r 'class abc foo' 

Parse error: syntax error, unexpected T_STRING, expecting '{' 

in Command line code on line 1
           

改進後:

% php -r 'class abc foo'

Parse error: syntax error, unexpected 'foo' (T_STRING), expecting '{' 

in Command line code on line
           

改進可能不十分明顯,但差別是現在已在錯誤消息中顯示偏移标記“foo”的值。

13. 數組到字元串轉換通知

如果您一直使用 PHP,則可能以随機出現在頁面中“Array”一詞結束程式設計,因為您嘗試直接輸出數組。每當将數組直接轉換為字元串時,都很有可能出現錯誤,現在有了一個針對這一情況的通知:

$a = [1,2,3];
echo $a; 
           

注意:數組到字元串轉換在example.phponlLine2中

14.函數類型提示的增強,(Callable typehint)

由于php是弱類型的語言,是以在php 5.0後,引入了函數類型提示的功能,支援對象和數組,其含義為對于傳入函數中的參數都進行類型檢查,舉個例子,有如下的類:

class bar {

}

function foo(bar $foo) {

}
           

其中函數foo中的參數規定了傳入的參數必須為bar類的執行個體,否則系統會判斷出錯。同樣對于數組來說,也可以進行判斷,比如:

function foo(array $foo) {

}

foo(array (
    1, 2, 3
)); // 正确,因為傳入的是數組

foo(123); // 不正确,傳入的不是數組

function my_function(callable $x)  {

     return $x();

}
           

而在php 5.4中,則支援對callable類型的支援。在以前, 我們如果希望一個函數接受一個回調函數作為參數, 那需要做很多額外的工作來檢查是否是可調用的正确的回調函數,例子如下:

function foo(callable $callback) {

  }
           

則:

foo("false"); //錯誤,因為false不是callable類型

foo("printf"); //正确

foo(function () {
}); //正确

class A {
    static function show() {
    
    }

}

foo(array (
    "A", "show" 
)); //正确
           

遺憾的是,PHP 5.4中,依然不支援對基本類型如字元,整形等的類型提示。

15.對時間統計的增強,高精度計時器

此次引入了$_SERVER['REQUEST_TIME_FLOAT']數組變量,微秒級精度(百萬分之一秒,float類型)。對于統計腳本運作時間會非常有用:

echo 'Executed in ', round(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], 2)

16. 上傳進度條Upload progress

檔案上傳進度回報, 這個需求在目前是越來越普遍, 比如大附件郵件. 在PHP5.4以前, 我們可以通過APC提供的功能來實作. 或者使用PECL擴充uploadprogress來實作.

雖然說, 它們能很好的解決現在的問題, 但是也有很明顯的不足:

  • 1. 他們都需要額外安裝(我們并沒有打算把APC加入PHP5.4)
  • 2. 它們都使用本地機制來存儲這些資訊, APC使用共享記憶體, 而uploadprogress使用檔案系統(不考慮NFS), 這在多台前端機的時候會造成麻煩.

從PHP的角度來說, 最好的儲存這些資訊的地方應該是SESSION, 首先它是PHP原生支援的機制. 其次, 它可以被配置到存放到任何地方(支援多機共享).

正因為此, Arnaud Le Blanc提出了針對Session報告上傳進度的RFC, 并且現在實作也已經包含在了PHP5.4的主幹中。

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

17. Zend Signal in PHP 5.4

在PHP5.4中, 根據由Rasmus送出的RFC, 引入了一套新的信号處理機制, 目的是為了使得信号屏蔽機制可以應用到任何SAPI中, 并且提高在這個過程中的PHP性能.

新的機制, 叫做zend signal, 它的理念, 來自Yahoo的”延遲信号處理”(Yahoo signal deferring mechanism), 而後, facebook把這套理念加入了PHP中, 為了提升PHP+Apache 1.X下PHP調用ap_block/ap_unblock的性能.

18. PHP 5.4 由Arnaud 引入了一個對三元式的優化方案.

我們都知道PHP用寫時複制來對變量複制做性能優化, 而在以前的三元式中, 卻每次都會複制, 這在操作數是大數組的情況下, 會造成性能問題:

<?php
    $a = range(1, 1000);
    $i = 0;
     
    $start = microtime(true);
    while (++$i < 1000) {
        $b = isset($a)? $a : NULL;
    }
     
    var_dump(microtime(true) - $start);
           

删除的特性

1)最後,我們集中整理了幾年來标記為已棄用的多個特性。這些特性包括 allow_call_time_pass_reference、define_syslog_variables、highlight.bg、register_globals、register_long_arrays、magic_quotes、safe_mode、zend.ze1_compatibility_mode、session.bug_compat42、session.bug_compat_warn 以及 y2k_compliance。

2) 備受指責的Register Globals已從 PHP 中完全删除。十年來,該特性一直以其頻繁發生的安全漏洞而著稱。2002年該特性被設定為預設關閉。2009年釋出的 PHP5.3 将該特性标記為“棄用”,想必從那時起,大部分開發人員已經不再使用它。

3)除了這些特性之外,magic_quotes 可能是最大的危險。在早期版本中,未考慮因 magic_quotes 出錯導緻的後果,簡單編寫且未采取任何舉措使自身免受 SQL 注入攻擊的應用程式都通過 magic_quotes 來保護。如果在更新到 PHP 5.4 時未驗證已采取正确的 SQLi 保護措施,則可能導緻安全漏洞。

4)PHP 中的break和continue語句之後可以跟上一個參數用來指明跳出的循環層數。如果不指定參數,它會像 VB、C#或 Java 一樣跳出最内層的循環。在 PHP 5.4 之前,開發人員可以向 break 語句傳遞一個變量,而現在隻能傳遞常量。

5)PHP 允許參數按引用傳遞。在早期版本中,你可以通過為調用點添加修飾來指明變量按引用傳遞。在 PHP 5.4 中,該選項已被移除。相反,現代 PHP 程式設計隻需要在函數聲明時指定按引用傳遞即可。與 C# 不同,你不需要同時在聲明和調用點指定按引用傳遞。

其他改動和特性

  • 有一種新的“可調用的”類型提示,用于某方法采用回調作為參數的情況。
  • htmlspecialchars() 和 htmlentities() 現在可更好地支援亞洲字元,如果未在 php.ini 檔案中顯式設定 PHP default_charset,這兩個函數預設使用 UTF-8 而不是 ISO-8859-1。
  • <?=(精簡回顯文法)現在始終可用,無論 short_tags ini 設定的值為何。這應該使模闆化系統建立者感到滿意。
  • 會話 ID 現在預設通過 /dev/urandom(或等效檔案)中的熵生成,而不是與早期版本一樣成為必須顯式啟用的一個選項。
  • mysqlnd 這一捆綁的 MySQL 原生驅動程式庫現在預設用于與 MySQL 通信的各種擴充,除非在編譯時通過 ./configure 被顯式覆寫。

可能還有 100 個小的改動和特性。從 PHP 5.3 更新到 5.4 應該極為順暢,但請閱讀遷移指南加以確定。如果您從早期版本更新,執行的操作可能稍多一些。請檢視以前的遷移指南再開始更新。

PHP 的下一步規劃是什麼?

我們沒有對 PHP 進行長期規劃。PHP 将随 Web 一起發展。我們不知道 5-10 年内的重要 Web 趨勢和技術将是什麼,但知道通過我們的不斷付出,PHP 必将存在。

短期内,我們通過“internals”郵件清單讨論 PHP 開發,并且就大特性達成共識時,它将發展為 RFC。您可以在wiki.php.net/rfc中找到 RFC。一旦我們表決同意釋出一組極佳的新特性,并且對這些特性進行了正确實作和測試,我們便開始籌備推出新版本。

PHP 随 Web 發展并保持穩定的市場佔有率,在全球所有網站中,大約三分之一的網站都使用它。其中不僅包括一些最大的網站,而且還包括很大一部分最小的網站。我是在最小網站上單獨設定 PHP 的:擴充是自然而然的事情,甚至是預期的特征,也是強烈吸引工程師的特征,但縮減不太正常,并且在某些情況下更困難。如果您找到适當的平衡,并且可以将同一代碼庫用于宿舍出租乃至擁有數十億美元資産的公司,那麼您就真正掌握了這種語言。

PHP 5.4版本将是最後一個支援Windows XP 和 Windows 2003的版本,今後将不再提供針對這些作業系統的二進制包。

PHP 5.4 will be the last series to support Windows XP and Windows2003. We will not provide binary packages for these Windows versionsafter PHP 5.4.