看完這篇,你會明白國內的PHP環境和ThinkPHP為啥要採用PHP5.3甚至更高的版本。
截至目前(2014.2), PHP 的最新穩定版本是 PHP5.5,
但有差不多一半的使用者仍在使用已經不在維護[註] 的PHP5.2, 其餘的一半使用者在使用PHP5.3 [註].
因為PHP 那「集百家之長」的蛋痛語法,加上社群氛圍不好,很多人對新版本,新特徵並無興趣。 本文將會介紹自 PHP5.2 起,直到 PHP5.6 中增加的新特徵。 PHP5.2 以前:autoload, PDO 和MySQLi, 類型限制
PHP5.2:JSON 支援
PHP5.3:棄用的功能,匿名函數,新增靜態方法,命名空間,後期靜態綁定,Heredoc 和Nowdoc, const, 三元運算符,Phar
PHP5.4:Short Open Tag, 陣列簡寫形式,Traits, 內建Web 伺服器,細節修改
PHP5.5:yield, list() 用於foreach,細部修改
PHP5.6: 常數增強,可變函數參數,命名空間增強
註:已於2011年1月停止支援: http://www.php.net/eol.php註:http://w3techs.com/technologies/details/pl-php/5/all
PHP5.2以前(2006前)順便介紹一下 PHP5.2 已經出現但值得介紹的特徵。 autoload大家可能都知道__autoload() 函數,如果定義了該函數,那麼當在程式碼中使用一個未定義的類別的時候,該函數就會被調用,你可以在該函數中加載對應的類別實作文件,例如:
-
function __autoload($classname ce("{$classname}.php" )
-
}
複製程式碼-
但該函數已經不被建議使用,因為項目中只有一個項目中只有一個不具有這樣的因素允許函數重名。但當你使用一些類別庫的時候,難免會出現多個autoload 函數的需要,於是spl_autoload_register() 取而代之:
spl_autoload_register
(spl_autoload_register(
- { require_once("{$classname}.php")
- 複製程式碼spl_autoload_register() 會將一個函數註冊到autoload 函數清單中,當出現未定義的類別的時候,SPL [註] 會按照註冊的倒序逐個呼叫被註冊的autoload 函數,這意味著你可以使用spl_autoload_register() 註冊多個autoload
函數.
-
註:SPL: Standard PHP Library, 標準 PHP 函式庫, 被設計用來解決一些經典問題(如資料結構).PDO 和 MySQLi即 PHP Data Object, PHP 資料對象,這是 PHP 的新式資料庫存取介面。 依照傳統的風格,存取MySQL 資料庫應該是這樣子:
- // 連接伺服器,選擇資料庫
-
$conn calhost" , "user", "password"); ;
-
// 執行 SQL 查詢$type =
$_POST- [
'type'-
];['
- "SELECT * FROM `table` WHERE `type` = {$type}";$result = mysql_query((
-
// 列印結果 while
(-
$row = myOC_ ))
{ -
foreach(
$row -
as $k => "{$k}: {$v}n" ; }
-
//清除
$result-
);mysql_close ($conn);複製程式碼為了能夠讓程式碼實現資料庫無關,即一段程式碼同時適用於多種資料庫(例如以上程式碼僅適用於MySQL),PHP 官方設計了PDO.除此之外,PDO 還提供了更多功能,例如:?物件導向風格的介面?SQL預編譯(prepare), 佔位符語法?更高的執行效率,作為官方推薦,有特別的效能最佳化?更高的執行效率,作為官方推薦,有特別的效能最佳化?大部分SQL資料庫,更換資料庫不需要改動程式碼
- 上面的程式碼用PDO 實作將會是這樣:
- // 連接到資料庫 PDO("mysql:host=localhost;dbname=database", "user", // 預編譯SQL, 綁定參數$query =
- $conn->
- . type` = :type" );
- $query->bindParam("type" ]);
- // 執行查詢並列印結果 foreach( as $row)
- {
-
foreach
- ($ $v) print " {$k}: {$v}n"; }
-
複製代碼
-
複製代碼 ,那麼你最好學習和使用PDO.但如果你需要使用MySQL 所特有的高級功能,那麼你可能需要嘗試一下MySQLi, 因為PDO 為了能夠同時在多種數據庫上使用,不會包含那些MySQL獨有的功能。 MySQLi 是 MySQL 的增強接口,同時提供面向過程和麵向對象接口,也是目前推薦的 MySQL 驅動,舊的C風格 MySQL 接口將會在今後被默認關閉。 MySQLi 的用法和以上兩段程式碼相比,沒有太多新概念,在此不再給出範例,可以參考 PHP 官網文件 [註]。
- 註:http://www.php.net/manual/en/mysqli.quickstart.php
類型約束透過型別約束可以限制參數的型別,不過此機制並不完善,目前僅適用於類別和callable(可執行型別) 以及array(數組), 不適用於string 和int.
- // 限制第一個參數為 MyClass, 第二個參數為執行型,第三個參數為陣列
-
function callable $b, array $c) { }
-
複製程式碼PHP5. 2
- (2006-2011)JSON 支援包括json_encode(), json_decode() 等函數,JSON 算是在Web 領域非常常用的資料交換格式,可以被JS 直接支持,JSON 實際上是JS 語法的一部分。
-
JSON 系列函數,可以將PHP 中的陣列結構與JSON 字串進行轉換:
$array
=
"value", "array"
- => array , 3, 4));$json = json_encode( "{$json}n"; $object = json_decode($json); object);複製程式碼
- 輸出:{"key":"value",
- ,3 ,4
- ]}
- stdClass Object ]
=>-
value [
array
]
=> -
Array [0] => [1]
- [2]
- =>
- [3] => 4
- ) )複製代碼值得注意的是json_decode() 預設會傳回物件而非數組,如果需要傳回數組需要將第二個參數設為true.
- PHP5.3(2009-2012)PHP5.3 算是一個非常大的更新,新增了大量新特徵,同時也做了一些不向下兼容的修改。 棄用的功能以下幾個功能被棄用,若在設定檔中啟用,則 PHP 會在執行時發出警告。 Register Globals這是php.ini 中的一個選項(register_globals), 開啟後會將所有表單變數($_GET和$_POST)註冊為全域變數.看下面的範例:
-
if(isAuth())
-
$authorized if($authorized
- ) include("page.php");
-
複製程式碼 然後決定是否顯示頁.
但由於並沒有事先把$authorized 初始化為false, 當register_globals 打開時,可能訪問/auth.php?authorized=1 來定義該變數值,繞過身份驗證。
該特徵屬於歷史遺留問題,在 PHP4.2 中被預設關閉,在 PHP5.4 中被移除。 Magic Quotes對應 php.ini 中的選項 magic_quotes_gpc, 這個特徵同樣屬於歷史遺留問題,已經在 PHP5.4 中移除。 該特徵會將所有使用者輸入進行轉義,這看起來不錯,在第一章中我們提到要將使用者輸入轉義。 但是 PHP 並不知道哪些輸入會進入 SQL , 哪些輸入會進入 Shell, 哪些輸入會被顯示為 HTML, 所以很多時候這種轉義會造成混亂。 Safe Mode很多虛擬主機供應商使用 Safe Mode 來隔離多個用戶,但 Safe Mode 存在諸多問題,例如某些擴充功能並不按照 Safe Mode 來進行權限控制。 PHP官方建議使用作業系統的機制來進行權限隔離,讓Web伺服器以不同的使用者權限來運行PHP解釋器,請參閱第一章中的最小權限原則.匿名函數也叫閉包(Closures), 經常被用來臨時性地創建一個無名函數,用於回調函數等用途。
-
$func = function($arg print
- $arg;
- };
- $func("Hello World"
- );"Hello World"
- ); $func .可以看到定義匿名函數依舊使用function 關鍵字,只不過省略了函數名,直接是參數列表。 然後我們又呼叫了 $func 所儲存的匿名函數。
匿名函數也可以用use 關鍵字來捕捉外在變數:
function arrayPlus( { array_walk
- ($array, function use($num
){-
$v
+=-
$num; });} 上面的程式碼定義了一個arrayPlus() 函數(這不是匿名函數), 它會將一個數組($array)中的每一項,加上一個指定的數字($num).在arrayPlus() 的實現中,我們使用了array_walk()函數,它會為一個陣列的每一項執行一個回呼函數,也就是我們定義的匿名函數。 在匿名函數的參數列表後,我們用 use 關鍵字將匿名函數外的 $num 捕捉到了函數內,以便知道到底應該加上多少。 魔術方法:__invoke(), __callStatic()PHP 的物件導向體系中,提供了若干“魔術方法”,用於實現類似其他語言中的“重載”,如在存取不存在的屬性、方法時觸發某個魔術方法。 隨著匿名函數的加入,PHP 引入了一個新的魔術方法__invoke().該魔術方法會在將一個物件作為函數呼叫時被呼叫:
-
-
{
-
public ) { "A::__invoke(): {$str}";
-
}
-
= new A
;-
$a
(-
"Hello World");
-
::
- __invoke(): Hello World
-
命名空間PHP的命名空間有著前無古人後無來者的無比蛋疼的語法:
-
phpphp?該聲明語句必須在文件第一行。 // 命名空間中可以包含任意程式碼,但只有 **類別, 函數, 常數** 受命名空間影響。
namespace
XXOOTest;
- 全域命名空間。
- class A{}
-
/T .- namespace
Other- Test2
;-
/存在
- $a = new XXOOTestA
- ;
- class B
- ( 你也可以用花括號定義第三個命名空間 namespace Other
- {
- =
-
new Test2 B;
-
// 導入函數和常數。
- use
XXOOTestA -
as
}A- as 複製程式碼更多關於命名空間的文法介紹請參考官網[註].命名空間時常和autoload 一同使用,用於自動載入類別實作檔案:
-
spl_autoload_register
spl_autoload_register- function ($class) {
(-
"\", "/", $class)); }
-
}
- );化一個類別XXOOTestA 的時候,這個類別的完整限定名會被傳遞給autoload 函數,autoload 函數將類別名稱中的命名空間分隔符號(反斜杠)替換為斜杠,並包含對應檔案。 這樣可以實現類別定義檔分級儲存,按需自動載入。
註:http://www.php.net/manual/zh/language.namespaces.php
後期靜態綁定
PHP 的OPP 機制,具有繼承和類似虛函數的功能,例如以下的程式碼:class Aclass A
-
class A
public-
function
callFuncXXOO-
() $this->funcXXOO
();-
}-
public
function-
funcXXOO()
- return
- "A::funcXXOO()";"A::funcXXOO()";
- }
- } ends A
{-
public-
public
function- funcXXOO
()-
{ "B::funcXXOO";
-
}
-
} }
- }
- } }
- }
- }
- )
-
$b = new
- FuncXXOO();複製程式碼
輸出是:
B::
- funcXXOO複製代碼
可以看到,當A 中使用$this->funcXXOO() 時,體現了「虛函數」的機制,實際呼叫的是B::funcXXOO().然而如果將所有函數都改為靜態函數:
-
class A
-
{
- function callFuncXXOO() {
- print self
- :: } static
public-
public
function- funcXXOO
()-
{ ::funcXXOO()"; }
-
}
-
}
-
class B
extends-
static
- public
-
function funcXXOO ()
{-
- } } $b
- = new
- B; 複製程式碼
情況就沒這麼樂觀了,輸出是:-
A
::-
funcXXOO()
-
關鍵字給了一個新功能:後期靜態綁定:
-
class A {
-
function callFuncXXOO ()
{
print-
();
}
- // ...
- }
-
// B::funcXXOO
複製程式碼-
Heredoc 和NowdocPHP5.3 對Heredoc 以及Heredoc 和Nowdoc
- PHP5.3 對Heredoc 以及Heredoc 和NowdocPHP5.3 對Heredoc 以及Heredoc 和NowdocPHP5.3 對Heredoc 以及Heredoc 和NowdocPHP5.3 對Heredoc 以及Heredoc 和NowdocPHP5.3 對Heredoc 以及Heredoc 和NowdocPHP5.3 對Heredoc 以及Heredoc 和NowdocPHP5.3 對Heredoc 以及Heredoc 和NowdocPHP5。
-
Heredoc 的行為類似一個雙引號字串:
- $name =
- TEXT
-
My
- name is
- "{$name}".
Heredoc 以三個左尖括號開始,後面跟著一個識別碼(TEXT), 直到一個同樣的頂格的識別碼(不能縮排)結束。 就像雙引號字串一樣,其中可以嵌入變數。 Heredoc 也可以用於函數參數,以及類別成員初始化:
-
var_dump(EOD
- (EOD EOD
-
);-
-
class-
A const xx
=-
EOD -
Hello WorldEOD
public-
$oo =
EOD-
Hello-
World-
EOD;EOD; Nowdoc 的行為像一個單引號字串,不能在其中嵌入變數,和Heredoc 唯一的差別就是,三個左尖括號後的識別字要以單引號括起來:
-
$name = "MyName"
- 'TEXT'
- My name
is} name
is. TEXT-
;複製代碼輸出:
-
My name is
"{$a."用const 定義常數-
PHP5.3 起同時支援在全域命名空間和類別中使用const 定義常數。 舊式風格:define("XOOO"
,- 程式碼新式風格:
const
XXOO =- "Value"; // 正確
const
XXOO = - const XXOO = 2 *
617;
echo $a -
? $a : "No Value";
複製程式碼
可簡寫成:
-
echo $a ?: "No Value";個部分,會預設用第一個部分代替。
Phar
Phar即PHP Archive, 起初只是Pear中的一個庫而已,後來在PHP5.3被重新編寫成C擴展並內置到 PHP 中。
Phar用來將多個 .php 腳本打包(也可以打包其他檔案)成一個 .phar 的壓縮檔案(通常是ZIP格式)。 目的在於模仿 Java 的 .jar, 不對,目的是為了讓發布PHP應用程式更加方便。同時也提供了數位簽章驗證等功能。 .phar 檔案可以像.php 檔案一樣,被PHP引擎解釋執行,同時你還可以寫出這樣的程式碼來包含(require) .phar 中的程式碼:require "xxoo.phar"); -
require("phar://xxoo.phar/xo/ox.H更多資訊請參考官網[註].
註:- http://www.php.net/manual/zh/phar.using.intro.php
PHP5.4(2012-2013)Short Open TagShort Open Tag 自 PHP5.4 起總是可用。 在這裡集中講一下有關 PHP 起止標籤的問題。即:
php // Code...? 通常就是上面的形式,除此之外面有簡寫形式:
- /* Code... */ ?
- php echo $xxoo;?>
-
複製碼
簡寫成:?
複製程式碼這種簡寫形式被稱為 Short Open Tag, 在 PHP5.3 起被預設開啟,在 PHP5.4 起總是可用。 使用這種簡寫形式在 HTML 中嵌入 PHP 變數將會非常方便。 對於純 PHP 檔案(如類別實作檔案), PHP 官方建議頂格寫起始標記,同時 省略 結束標記。 這樣可以確保整個PHP 檔案都是PHP 程式碼,沒有任何輸出,否則當你包含該檔案後,設定Header 和Cookie 時會遇到一些麻煩[註].注:Header 和Cookie 必須在輸出任何內容之前被發送。 數組簡寫形式這是非常方便的一項特徵!
- // 原來的陣列寫法
-
$arr = array( "value", "key2" => "value2"); /
[-
"key"
=>-
"value", "key2" 複製程式碼Traits 所謂Traits就是“構件”,是用來取代繼承的一種機制。 PHP中無法進行多重繼承,但一個類別可以包含多個Traits.// Traits不能被單獨實例化,只能被類別所包含trait
public
function
sayHello()) sayHello- ())
echo -
'World!';
-
}
- } }
class-
MyHellooclass
- MyHellooclass
MyHello- // 將SayWorld中的成員包含進來
-
use
- SayWorld
;-
}
- MyHelloWorld();
-
// sayHello() 函數是來自 SayWorld 構件的
-
$xxoo->sayHello(); , 解決衝突,修改存取權限,為函數設定別名等等。
Traits中也同樣可以包含Traits. 篇幅有限不能逐個舉例,詳情參見官網[註].-
註:http://www.php.net/manual/zh/language.oop5.traitsguage. .php
內建 Web 伺服器- PHP從5.4開始內建一個輕量級的Web伺服器,不支援並發,定位是用於開發和調試環境。 在開發環境中使用它的確非常方便。
-
php -S localhost:8000
3個目錄 / 來訪問。
其中localhost是監聽的ip,8000是監聽的端口,可以自行修改。 很多應用中,都會進行URL重寫,所以PHP提供了一個設定路由腳本的功能:php -
-S . php複製程式碼這樣一來,所有的請求都會由index.php來處理。
你也可以使用 XDebug 來進行斷點除錯。
細部修改PHP5.4 新增了動態存取靜態方法的方式:
$func = { $func}();-
複製程式碼新增在實例化時存取類別成員的特徵:
()-
xxoo-
();複製程式碼新增支援對函數傳回陣列的成員存取解析(此寫法在先前版本是會回覆錯誤的): ()[
0
];
複製代碼-
PHP5.5(2013起)PHP5.5(2013起)yield返回值。
function number10
() { i =-
1;
$i -
10-
; $i += yield $i; } 複製程式碼此函數的回傳值是一個陣列:list() 用於foreach可以用list() 在foreach 解析巢狀的陣列:
-
$array = [
-
2, 3], [ 6
],-
]; foreach (
$array -
as $b,
- $c))
- echo "{$a} {$b} {$c}n"; 2 3 4 5
- 6 MySQLi, 參見前文。 不再支援Windows XP.
可用 MyClass::class 取到一個類別的完整限定名(包括命名空間)。
empty() 支援表達式作為參數。
-
try-catch 結構新增 finally 區塊。 PHP5.6較好的常數定義常數時允許使用先前定義的常數來計算:
- const const B
= A
+ 1 C { const STR =
- "hello";
self-
::STR + ", world "; }
-
複製程式碼
-
$arg =
C -
::STR2
)-
複製程式碼更好的可變函數參數用來取代func_get_args()
-
function add(...$arg $result =
-
0 ;
-
foreach($args as $result
+=-
$arg; return $result;
-
}複製碼
-
複製碼。 =
- [2
,
3
];
-
$arr); // 結果為 6複製碼命名空間
- 命名空間支援常數和函數:Name命名空間支援常數與{ const FOO =
-
42;
{
echo __FUNCTION__."n"-
; }
}-
-
name use const NameSpaceFOO; use
-
function
Name- echo FOO
.-
"n"; f
();-
}
以上就介紹了PHP52至56的新增功能詳解,包括了方面的內容,希望對PHP教程有興趣的朋友有所幫助。