PHP Conference Japan 2024

新功能

純量類型宣告

純量類型宣告有兩種形式:強制型(預設)和嚴格型。現在可以強制執行以下參數類型(強制或嚴格):字串(字串)、整數(int)、浮點數(float)和布林值(bool)。它們增強了 PHP 5 中引入的其他類型:類別名稱、介面、陣列可呼叫

<?php
// 強制模式
function sumOfInts(int ...$ints)
{
return
array_sum($ints);
}

var_dump(sumOfInts(2, '3', 4.1));

上述範例將輸出

int(9)

若要啟用嚴格模式,必須將單一的 declare 指令放置在檔案頂部。這表示純量類型宣告的嚴格性是依每個檔案設定的。此指令不僅會影響參數的類型宣告,也會影響函式的回傳類型(請參閱回傳類型宣告、內建 PHP 函式和已載入擴充功能的函式)。

有關純量類型宣告的完整文件和範例,請參閱類型宣告參考。

回傳類型宣告

PHP 7 新增了對回傳類型宣告的支援。與引數類型宣告類似,回傳類型宣告會指定將從函式傳回的值的類型。與引數類型宣告一樣,回傳類型宣告可以使用相同的類型

<?php

function arraysSum(array ...$arrays): array
{
return
array_map(function(array $array): int {
return
array_sum($array);
},
$arrays);
}

print_r(arraysSum([1,2,3], [4,5,6], [7,8,9]));

上述範例將輸出

Array
(
    [0] => 6
    [1] => 15
    [2] => 24
)

有關回傳類型宣告的完整文件和範例,請參閱回傳類型宣告參考。

Null 聯合運算子

已新增 Null 聯合運算子(??)作為常見情況的語法糖,在這種情況下,需要將三元運算子與 isset() 結合使用。如果第一個運算元存在且不是 null,則它會傳回第一個運算元;否則,它會傳回第二個運算元。

<?php
// 擷取 $_GET['user'] 的值,如果不存在則傳回 'nobody'
$username = $_GET['user'] ?? 'nobody';
// 這相當於:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// 可以串連聯合:這會從 $_GET['user']、$_POST['user'] 和
// 'nobody' 中傳回第一個定義的值。
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

太空船運算子

太空船運算子用於比較兩個表達式。當 $a 分別小於、等於或大於 $b 時,它會傳回 -1、0 或 1。比較會根據 PHP 的慣用類型比較規則執行。

<?php
// 整數
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1

// 浮點數
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// 字串
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
?>

使用 define() 的常數陣列

現在可以使用 define() 定義陣列常數。在 PHP 5.6 中,它們只能使用const 定義。

<?php
define
('ANIMALS', [
'dog',
'cat',
'bird'
]);

echo
ANIMALS[1]; // outputs "cat"
?>

匿名類別

已透過 new class 新增對匿名類別的支援。這些可以取代完整的類別定義,用於拋棄式物件。

<?php
interface Logger {
public function
log(string $msg);
}

class
Application {
private
$logger;

public function
getLogger(): Logger {
return
$this->logger;
}

public function
setLogger(Logger $logger) {
$this->logger = $logger;
}
}

$app = new Application;
$app->setLogger(new class implements Logger {
public function
log(string $msg) {
echo
$msg;
}
});

var_dump($app->getLogger());
?>

上述範例將輸出

object(class@anonymous)#2 (0) {
}

完整的說明文件可以在匿名類別參考中找到。

Unicode 碼位跳脫語法

這會採用十六進位形式的 Unicode 碼位,並將該碼位以 UTF-8 輸出到雙引號字串或 heredoc 中。任何有效的碼位都會被接受,前導 0 是可選的。

<?php

echo "\u{aa}", PHP_EOL;
echo
"\u{0000aa}", PHP_EOL;

echo
"\u{9999}", PHP_EOL;

echo <<<EOT
\u{01f418}
EOT;

?>

上述範例將輸出

ª
ª (same as before but with optional leading 0's)
香

Closure::call()

Closure::call() 是一種更高效能、更簡潔的方式,可以暫時將物件範圍繫結到閉包並調用它。

<?php
class A {private $x = 1;}

// Pre PHP 7 code
$getX = function() {return $this->x;};
$getXCB = $getX->bindTo(new A, 'A'); // intermediate closure
echo $getXCB();

// PHP 7+ code
$getX = function() {return $this->x;};
echo
$getX->call(new A);

上述範例將輸出

1
1

已過濾的 unserialize()

此功能旨在於反序列化來自不受信任資料的物件時,提供更好的安全性。它透過讓開發人員將可以反序列化的類別列入白名單,來防止可能的程式碼注入。

<?php

// 將所有物件轉換為 __PHP_Incomplete_Class 物件
$data = unserialize($foo, ["allowed_classes" => false]);

// 將所有物件轉換為 __PHP_Incomplete_Class 物件,但 MyClass 和 MyClass2 的物件除外
$data = unserialize($foo, ["allowed_classes" => ["MyClass", "MyClass2"]]);

// 預設行為(與省略第二個參數相同),接受所有類別
$data = unserialize($foo, ["allowed_classes" => true]);

IntlChar

新的 IntlChar 類別旨在公開額外的 ICU 功能。該類別本身定義了許多可用來操作 unicode 字元的靜態方法和常數。

<?php

printf
('%x', IntlChar::CODEPOINT_MAX);
echo
IntlChar::charName('@');
var_dump(IntlChar::ispunct('!'));

上述範例將輸出

10ffff
COMMERCIAL AT
bool(true)

為了使用此類別,必須安裝 Intl 擴充功能。

期望

期望是對較舊的 assert() 函式的向後相容增強功能。它們允許在生產程式碼中進行零成本的斷言,並在斷言失敗時提供拋出自訂異常的能力。

雖然舊的 API 為了相容性而繼續維護,assert() 現在是一種語言結構,允許第一個參數是一個運算式,而不僅僅是一個要評估的 字串 或一個要測試的 布林 值。

<?php
ini_set
('assert.exception', 1);

class
CustomError extends AssertionError {}

assert(false, new CustomError('Some error message'));
?>

上述範例將輸出

Fatal error: Uncaught CustomError: Some error message

有關此功能的完整詳細資訊,包括如何在開發和生產環境中設定它,可以在 assert() 語言結構的手冊頁面中找到。

群組 use 宣告

現在可以將從同一個 namespace 匯入的類別、函式和常數,分組在單個 use 語句中。

<?php
// Pre PHP 7 code
use some\namespace\ClassA;
use
some\namespace\ClassB;
use
some\namespace\ClassC as C;

use function
some\namespace\fn_a;
use function
some\namespace\fn_b;
use function
some\namespace\fn_c;

use const
some\namespace\ConstA;
use const
some\namespace\ConstB;
use const
some\namespace\ConstC;

// PHP 7+ code
use some\namespace\{ClassA, ClassB, ClassC as C};
use function
some\namespace\{fn_a, fn_b, fn_c};
use const
some\namespace\{ConstA, ConstB, ConstC};
?>

產生器回傳運算式

此功能建立在 PHP 5.5 中引入的產生器功能之上。它允許在產生器中使用 return 語句,以便傳回最終運算式(不允許依參考傳回)。可以使用新的 Generator::getReturn() 方法取得此值,該方法只能在產生器完成產生值後使用。

<?php

$gen
= (function() {
yield
1;
yield
2;

return
3;
})();

foreach (
$gen as $val) {
echo
$val, PHP_EOL;
}

echo
$gen->getReturn(), PHP_EOL;

上述範例將輸出

1
2
3

能夠從生成器明確地返回最終值是一項很方便的功能。這是因為它允許生成器返回一個最終值(可能來自某種協程計算),而該值可以由執行生成器的客戶端程式碼專門處理。這比強迫客戶端程式碼先檢查是否已產生最終值,然後再專門處理該值要簡單得多。

生成器委派

現在,生成器可以自動委派給另一個生成器、Traversable 物件或 array,而無需使用 yield from 建構在最外層的生成器中編寫樣板程式碼。

<?php
function gen()
{
yield
1;
yield
2;
yield from
gen2();
}

function
gen2()
{
yield
3;
yield
4;
}

foreach (
gen() as $val)
{
echo
$val, PHP_EOL;
}
?>

上述範例將輸出

1
2
3
4

使用 intdiv() 的整數除法

新的 intdiv() 函數會執行其運算元的整數除法並返回結果。

<?php
var_dump
(intdiv(10, 3));
?>

上述範例將輸出

int(3)

Session 選項

session_start() 現在接受一個 array 選項,這些選項會覆蓋通常在 php.ini 中設定的 session 設定指令

這些選項也已擴展以支援 session.lazy_write,預設為開啟,並且僅在 session 資料已變更時才導致 PHP 覆寫任何 session 檔案,以及 read_and_close,這是一個只能傳遞給 session_start() 的選項,表示應讀取 session 資料,然後立即關閉 session,不做任何變更。

例如,將 session.cache_limiter 設定為 private,並在讀取 session 後立即關閉它

<?php
session_start
([
'cache_limiter' => 'private',
'read_and_close' => true,
]);
?>

preg_replace_callback_array()

當使用 preg_replace_callback() 函數時,新的 preg_replace_callback_array() 函數可讓程式碼寫得更簡潔。在 PHP 7 之前,每個正規表示式需要執行的回呼函數都需要在回呼函數中加入許多分支。

現在,可以使用關聯陣列將回呼函數註冊到每個正規表示式,其中鍵是正規表示式,值是回呼函數。

CSPRNG 函數

已新增兩個新函數,以跨平台方式產生加密安全的整數和字串:random_bytes()random_int()

list() 永遠可以解包實作 ArrayAccess 的物件

先前,list() 無法保證能與實作 ArrayAccess 的物件正確運作。此問題已修正。

其他功能

  • 已新增對複製物件的類別成員存取,例如 (clone $foo)->bar()
新增註解

使用者貢獻的註解 2 則註解

60
Adrian Wiik
4 年前
一個用於記住太空船運算子運算式返回值的良好經驗法則是將太空船運算子替換為減號 (-)。如果結果為負數、0 或正數,則運算式將分別返回 -1、0 或 1。

範例
<?php
echo 5 <=> 8; // 5 - 8 = -3, 印出 -1
echo 2 <=> 2; // 2 - 2 = 0, 印出 0
echo 4 <=> 2; // 4 - 2 = 2, 印出 1
16
Julian Sawicki
4 年前
在 php 7.0 中,可以用類似 JavaScript 的方式柯里化函數。

<?php

// 一個柯里化函數
function add($a) {
return function(
$b) use ($a) {
return
$a + $b;
};
}

// 在 PHP 7 中呼叫柯里化函數
$result = add(10)(15);

var_dump($result); // int 25

?>

這種方式的柯里化在 php 5.6 中是不可能的。
To Top