談到版本,不得不聊聊歷史。筆者第一次接觸到 PHP 時,那時網路上正如火如茶地興起一陣自架論壇的熱潮,PHPBB 2,一款以 PHP 4 開發的論壇軟體,雨後春筍般地出現,當然筆者也不例外(不小心透露了年紀 ^^"),在什麼都不懂的情況下,慢慢照著網路上的教學文章租用虛擬主機,一步一步安裝。
好不容易把論壇架起來後,要裝外掛擴充功能,那種方式應該會讓現在的年輕人覺得匪夷所思,居然是開啟 Notepad,依照外掛安裝的說明檔,搜尋特定字串的行數,然後插入說明檔內標示的程式碼段落,一個外掛可能有二十幾處需要修改 PHPBB 2 原始碼的地方,不斷剪下、貼上。一不小心插錯位置,網站就掛了。雖然頗有樂趣,但也改的步步驚心呀。
PHP 4
依筆者的過往體驗,可見得當時 PHP 4 還是一個很陽春的語言,不但沒有套件管理器,也沒自動加載機制,一套軟體要 include 所有檔案,耗用的記憶體量實在很肥厚,線上沒多少人就被主機商警告了 ><"。不過沒辦法,要裝別人寫好的函式庫,就是要整包下載,include 起來,不然就是挑自己想要的程式片段剪貼過去,PHP 記憶體吃的兇是當時的痛點呀。
PHP 5.3
這種情況一直到了 2009 年 7 月 30 日,PHP 5.3 版釋出,開始有了命名空間 (Namespace)、匿名函式 (anonymous functions)、閉包 (Closure) 等等功能。開始有了轉變。
PHP 5.4
2012 年,和 PHP 5.4 版同一天釋出的 Composer 問市,PHP 終於有了其生態系專用的套件管理軟體。Composer 有效管理套件彼此之間的依賴關係,自動加載機制讓有用到的功能才載入,節省記憶體用量,不單如此,Composer 讓整個 PHP 更往一個成熟的程式語言發展。
因此筆者就以 Composer 的生日作為 PHP 各版本的基準,以表格的方式列出自 5.4 起,時至今日的 7.4 版,各版本之間的差異點。
版本差異
如果你想讓作品可以向下相容讓更多人使用,有些語法是否能在某些版本運作,不得不去注意。
點擊版本號連結可至官方文件閱讀詳細的變更,下表主要列出不可當作 Class 及 function 名稱的表留字以及已被移除的函式。筆者整理了大概的,值得注意的補充另外列出。
版本號 | 釋出日期 | 保留字 | 移除 |
---|---|---|---|
5.4 | 2012/3/1 | trait, callable, insteadof | define_syslog_variables(), import_request_variables(), session_is_registered(), session_register(), session_unregister(), mysqli_bind_param(), mysqli_bind_result(), mysqli_client_encoding(), mysqli_fetch(), mysqli_param_count(), mysqli_get_metadata(), mysqli_send_long_data(), mysqli::client_encoding(), mysqli_stmt::stmt() |
5.5 | 2013/7/20 | - | php_logo_guid(), php_egg_logo_guid(), php_real_logo_guid(), zend_logo_guid(), |
5.6 | 2014/8/28 | - | - |
7.0 | 2015/12/3 | bool, int, float, string, NULL, TRUE, FALSE | call_user_method(), call_user_method_array(), mcrypt_generic_end, mcrypt_ecb(), mcrypt_cbc(), mcrypt_cfb(), mcrypt_ofb(), datefmt_set_timezone_id(), IntlDateFormatter::setTimeZoneID(), set_magic_quotes_runtime(), magic_quotes_runtime(), set_socket_blocking(), imagepsbbox(), imagepsencodefont(), imagepsextendfont(), imagepsfreefont(), imagepsloadfont(), imagepsslantfont(), imagepstext(), ereg 系列函式, mysql 系列函式, mssql 系列函式 |
7.1 | 2016/12/1 | void, iterable, | - |
7.2 | 2017/11/30 | object | |
7.3 | 2018/12/6 | - | - |
7.4 | 2019/12/28 | fn | |
8.0 | 2020/1/6 | match | each(), create_function(), __autoload(), image2wbmp(), png2wbmp(), jpeg2wbmp(), gmp_random(), ldap_sort(), ldap_control_paged_result(), ldap_control_paged_result_response(), oci_internal_debug(), ociinternaldebug(),hebrevc(), convert_cyr_string(), money_format(), ezmlm_hash(), restore_include_path(), get_magic_quotes_gpc(), get_magic_quotes_runtime(), fgetss(), gzgetss(), |
8.1 | 2021/11/25 | readonly |
根據網路上可找到的效能評分報告,PHP 7.0 對上 5.6 有超過一倍以上的效能突破,此後每一個版本都有效能的些許提升,PHP 7.4 對 PHP 7.3 又較大幅度的提升。由於測試不是筆者進行的,礙於版權問題不方便抓圖,如有興趣,請搜尋 PHP version branchmark 可找到相關文章。
雖然效能上提升,但每一個中版號的更新都有必須注意的變動。除了閱讀官方文件外,最好的辦法就是針對你的作品進行單元測試 (Unit Test)了,當覆蓋率達到百分之一百,並配合不同的 PHP 版本作測試,基本上不必太過擔心會有出包的情況發生。
PHP 5.4
Trait
引進了 Trait (特性),對於在不同的類別 (Class) 都會用到相同的方法 (Method),則可以把相同的程式碼獨立出來成為一個特性。
又或者一個類別過於龐大,例如擁有 30 個以上的方法,可以適時把這些方法分門別類放到不同的特性中,增加程式碼的可讀性,便於日後維護。
trait IpTrait
{
protected $ipAddress;
public function setIp($ip)
{
$this->ipAddress = $ip;
}
public function getIp()
{
return $this->ipAddress
}
}
使用 IpTrait,則使用 use
這個關鍵字。
class Kernel
{
use IpTrait;
}
此時 Kernel 這個類別擁有了 $ipAddress
這個 property 和它的 setIp
, getIp
兩個方法。
Array
可開始始用簡短的語法 []
來使用陣列。
$terry = [
'smart',
'handsome',
'programmer'
];
PHP 5.4 以前的用法:
$terry = array(
'smart',
'handsome',
'programmer'
);
PHP 5.5
引進生成器 (generators),雖然文件沒特別註明保留字,但生成器所會用到的 yield
這個字不能再使用於 class 及 function 的命名上。
PHP 5.6
基本上和 5.5 可無縫接軌,變更的地方少。
PHP 7.0
語法糖 ??
以往使用三元運算子,例如:
$action = $_POST['choice'] ? 'yes' : 'no';
假如 choice
這個 key 並不存在於 $_POST
則會出現錯誤。因此必須先檢查 $_POST['choice']
是否存在。
$action = $_POST['choice'] ?? 'no';
等於
if (isset($_POST['choice'])) {
$action = $_POST['choice'];
} else {
$action = 'no';
}
這和 PHP 5.3 的語法糖 ?:
類似,只不過會先檢查值是否存在。
Error
新增了 Error
這個類別,因此在專案中命名了 Error 這個 class 當作錯誤處理用,在 PHP 5.6 會運行的好好的,一旦到了 PHP 7.0 則會因為類別已存在而噴錯。
返回值類型
function test(string $name): string
{
return 'this is a string';
}
可以制定返回值類型,如果不符合則出現錯誤訊息。
PHP 7.1
- 在函式方法中新增了
null
這個類型。?
代表 null。 - 返回值新增了
void
這個類型。
function test(?string $name): void
{
var_dump($name);
}
$name
的值可以是 string 或 null。返回值為 void 代表沒有返回值。
PHP 8.0
PHP 7.4 升級到 8.0 預期會遇到許多相容性的問題,除了原本在 PHP 7.4 是 Warning 級別的錯誤,在 8.0 版則會是 Fatal Error。因此要升級前務必檢查自己的程式碼、使用的框架及套件是否使用到已停用的函式,以免遇到預期外的錯誤情況發生。
另外函式參數的改變,也常常會有 Fatal Error 的情況,例如:
像上圖 max
函式的例子,PHP 7.4 是 Warning 級別的錯誤,PHP 8.0 就噴 Fatal Error,因此升級前務必查看 log,看看自己的專案產生了多少的 Warning,必須全部排除再升級。
總結
本篇文章非在於介紹各版本的新功能,而是提醒相容性的問題。雖然升級到 PHP 8 以上可能會遇到問題,但也不能因為這樣而不去進行,因為在效能提升上的考量上,進行升級是非常划算的,也剛好可以盤點一下專案的 legacy code。
留言