PHP Conference Japan 2024

型別轉換

PHP 不需要在變數宣告中明確定義型別。在這種情況下,變數的型別由它儲存的值決定。也就是說,如果將字串賦值給變數 $var,則 $var 的型別為 字串。如果之後將 整數值賦值給 $var,它的型別將變為 整數

在某些情況下,PHP 可能會嘗試自動將值的型別轉換為另一種型別。存在的不同情況有:

  • 數值
  • 字串
  • 邏輯
  • 整數和字串
  • 比較
  • 函式

注意當一個值需要被解釋為不同的型別時,值本身並不會改變型別。

若要強制變數以特定類型進行評估,請參閱類型轉換一節。若要變更變數的類型,請參閱 settype() 函式。

數值上下文

這是使用算術運算子時的上下文。

在此上下文中,如果任一運算元是 浮點數(或無法被解釋為 整數),則兩個運算元都會被解釋為 浮點數,結果也將是 浮點數。否則,運算元將被解釋為 整數,結果也將是 整數。從 PHP 8.0.0 開始,如果其中一個運算元無法被解釋,則會拋出 TypeError

字串上下文

這是使用 echoprint字串插值 或字串串接運算子時的上下文。

在此上下文中,值將被解釋為 字串。如果值無法被解釋,則會拋出 TypeError。在 PHP 7.4.0 之前,會引發 E_RECOVERABLE_ERROR

邏輯上下文

這是使用條件式、三元運算子邏輯運算子時的上下文。

在此上下文中,值將被解釋為 布林值

整數和字串上下文

這是使用位元運算子時的上下文。

在此上下文中,如果所有運算元都是 字串 類型,則結果也將是 字串。否則,運算元將被解釋為 整數,結果也將是 整數。從 PHP 8.0.0 開始,如果其中一個運算元無法被解釋,則會拋出 TypeError

比較上下文

這是使用比較運算子時的上下文。

此上下文中發生的類型轉換在與各種類型比較的表格中進行說明。

函式上下文

這是將值傳遞給類型化參數、屬性或從宣告返回類型的函式返回時的上下文。

在此上下文中,值必須是該類型的值。存在兩個例外,第一個是:如果值是 整數 類型,而宣告的類型是 浮點數,則整數會轉換為浮點數。第二個是:如果宣告的類型是 *純量* 類型,則該值可轉換為純量類型,並且強制類型模式處於活動狀態(預設值),則該值可能會轉換為可接受的純量值。有關此行為的說明,請參見下文。

警告

內建函式會自動將 null 強制轉換為純量類型,此行為自 PHP 8.1.0 起已被*棄用*。

使用簡單類型宣告的強制類型

  • bool 類型宣告:值會被解讀為 bool
  • int 類型宣告:如果轉換定義明確,值會被解讀為 int。例如,字串是數值
  • float 類型宣告:如果轉換定義明確,值會被解讀為 float。例如,字串是數值
  • string 類型宣告:值會被解讀為 string

聯合類型強制類型轉換

strict_types 未啟用時,純量類型宣告會受到有限的隱式類型強制轉換的影響。如果值的確切類型不屬於聯合類型的一部分,則目標類型會按照以下優先順序選擇:

  1. int
  2. float
  3. string
  4. bool
如果該類型存在於聯合類型中,並且該值可以根據 PHP 現有的類型檢查語義強制轉換為該類型,則會選擇該類型。否則,將會嘗試下一個類型。

注意

作為例外,如果值是一個字串,並且 int 和 float 都是聯合類型的一部分,則首選類型由現有的數值字串語義決定。例如,對於 "42" 會選擇 int,而對於 "42.0" 會選擇 float

備註:

不在上述優先順序列表中的類型不符合隱式強制轉換的目標條件。特別是,不會發生對 nullfalsetrue 類型的隱式強制轉換。

範例 #1 類型被強制轉換為聯合類型一部分的範例

<?php
// int|string
42 --> 42 // 精確型別
"42" --> "42" // 精確型別
new ObjectWithToString --> "Result of __toString()"
// 物件永遠與 int 不相容,退回 string 型別
42.0 --> 42 // float 與 int 相容
42.1 --> 42 // float 與 int 相容
1e100 --> "1.0E+100" // float 值過大,超出 int 型別範圍,退回 string 型別
INF --> "INF" // float 值過大,超出 int 型別範圍,退回 string 型別
true --> 1 // bool 與 int 相容
[] --> TypeError // 陣列與 int 或 string 不相容

// int|float|bool
"45" --> 45 // 數值字串轉換為 int
"45.0" --> 45.0 // 數值字串轉換為 float

"45X" --> true // 非數值字串,退回 bool 型別
"" --> false // 非數值字串,退回 bool 型別
"X" --> true // 非數值字串,退回 bool 型別
[] --> TypeError // 陣列與 int、float 或 bool 不相容
?>

型別轉換

型別轉換將值轉換為所選的型別,方法是在要轉換的值之前用括號括住型別名稱。

<?php
$foo
= 10; // $foo 是一個整數
$bar = (bool) $foo; // $bar 是一個布林值
?>

允許的轉換類型如下:

備註:

(integer)(int) 轉型的一個別名。 (boolean)(bool) 轉型的一個別名。 (binary)(string) 轉型的一個別名。 (double)(real)(float) 轉型的別名。這些轉型並未使用標準的型態名稱,因此不建議使用。

警告

自 PHP 8.0.0 起,(real) 轉型別名已被棄用。

警告

自 PHP 7.2.0 起,(unset) 轉型已被棄用。請注意,(unset) 轉型與將 NULL 值賦值給變數或呼叫的結果相同。自 PHP 8.0.0 起,(unset) 轉型已被移除。

注意

(binary) 轉型和 b 前綴的存在是為了向前相容。目前 (binary)(string) 是相同的,但這可能會改變,因此不應依賴此行為。

備註:

轉型括號中的空格會被忽略。因此,以下兩個轉型是等效的

<?php
$foo
= (int) $bar;
$foo = ( int ) $bar;
?>

將字面字串和變數轉型為二進位字串

<?php
$binary
= (binary) $string;
$binary = b"binary string";
?>

注意: 除了將變數轉型為字串之外,也可以將變數用雙引號括起來。

<?php
$foo
= 10; // $foo 是一個整數
$str = "$foo"; // $str 是一個字串
$fst = (string) $foo; // $fst 也是一個字串

// 這會印出「它們是相同的」
if ($fst === $str) {
echo
"它們是相同的";
}
?>

在某些類型之間進行轉型時,其確切行為可能並不明顯。更多資訊,請參閱以下章節

注意由於 PHP 支援使用與 陣列 索引相同的語法,透過偏移量對 字串 進行索引,因此以下範例適用於所有 PHP 版本:

<?php
$a
= 'car'; // $a 是一個字串
$a[0] = 'b'; // $a 仍然是一個字串
echo $a; // bar
?>
更多資訊請參見標題為 透過字元存取字串 的章節。

新增註解

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

Raja
19 年前
將一個整數變數除以另一個整數變數,若結果非整數,將會透過自動轉換成浮點數 -- 您不需要將變數強制轉換為浮點數以避免整數截斷(例如在 C 語言中您會這樣做)

$dividend = 2;
$divisor = 3;
$quotient = $dividend/$divisor;
print $quotient; // 0.66666666666667
匿名
3 年前
強制轉換運算子的優先順序非常高,例如 (int)$a/$b 的計算方式為 ((int)$a)/$b,而不是 (int)($a/$b) [如果 $a 和 $b 都是整數,其結果會像 intdiv($a,$b)]。
截至 PHP 8.0,唯一的例外是冪運算子 ** [即 (int)$a**$b 的計算方式為 (int)($a**$b) 而不是 ((int)$a)**$b] 以及特殊的存取/呼叫運算子 ->、::、[] 和 () [即在 (int)$a->$b、(int)$a::$b、(int)$a[$b] 和 (int)$a($b) 中,強制轉換會最後作用於變數運算式的結果]。
fardelian
11 年前
將物件強制轉換為陣列很麻煩。範例

<?php

class MyClass {

private
$priv = 'priv_value';
protected
$prot = 'prot_value';
public
$pub = 'pub_value';
public
$MyClasspriv = 'second_pub_value';

}

$test = new MyClass();
echo
'<pre>';
print_r((array) $test);

/*
陣列
(
[MyClasspriv] => priv_value
[*prot] => prot_value
[pub] => pub_value
[MyClasspriv] => second_pub_value
)
*/

?>

是的,這看起來像是一個具有兩個同名鍵的陣列,而且受保護的欄位前面似乎加上了星號。但這不是真的

<?php

foreach ((array) $test as $key => $value) {
$len = strlen($key);
echo
"{$key} ({$len}) => {$value}<br />";
for (
$i = 0; $i < $len; ++$i) {
echo
ord($key[$i]) . ' ';
}
echo
'<hr />';
}

/*
MyClasspriv (13) => priv_value
0 77 121 67 108 97 115 115 0 112 114 105 118
*prot (7) => prot_value
0 42 0 112 114 111 116
pub (3) => pub_value
112 117 98
MyClasspriv (11) => second_pub_value
77 121 67 108 97 115 115 112 114 105 118
*/

?>

字元碼顯示受保護的鍵值前面會加上 '\0*\0',而私有鍵值前面會加上 '\0'.__CLASS__.'\0',因此在使用時要小心。
miracle at 1oo-percent dot de
18 年前
如果您想將字串自動轉換為浮點數或整數(例如,將 "0.234" 轉換為浮點數,將 "123" 轉換為整數),只需在字串中加上 0 即可 - PHP 會完成剩下的工作。

例如:

$val = 0 + "1.234";
($val 的類型現在是浮點數)

$val = 0 + "123";
($val 的類型現在是整數)
rmirabelle
14 年前
這裡提供的物件轉換方法並未考慮到您嘗試將物件轉換成的類別的類別階層。

/**
* 將物件轉換為特定類別。
* @param object $object
* @param string $class_name 要將物件轉換成的類別
* @return object
*/
public static function cast($object, $class_name) {
if($object === false) return false;
if(class_exists($class_name)) {
$ser_object = serialize($object);
$obj_name_len = strlen(get_class($object));
$start = $obj_name_len + strlen($obj_name_len) + 6;
$new_object = 'O:' . strlen($class_name) . ':"' . $class_name . '":';
$new_object .= substr($ser_object, $start);
$new_object = unserialize($new_object);
/**
* 新物件的類型正確,但
* 並未在其整個圖形中完全初始化。
* 要取得完整的物件圖形(包括父
* 類別資料),我們需要建立一個指定類別的新執行個體,
* 然後將新的屬性賦值給它。

*/
$graph = new $class_name;
foreach($new_object as $prop => $val) {
$graph->$prop = $val;
}
return $graph;
} else {
throw new CoreException(false, "在 DB::cast 中找不到要轉換的類別 $class_name");
return false; (返回 false)
}
}
ieee at REMOVE dot bk dot ru (ieee at REMOVE dot bk dot ru)
12 年前
有一些更簡短、更快(至少在我的機器上)的方法來執行類型轉換。
<?php
$string
='12345.678';
$float=+$string;
$integer=0|$string;
$boolean=!!$string;
?>
匿名
22 年前
印出或 echo 一個 FALSE 布林值或 NULL 值會產生一個空字串。
(string)TRUE //返回 "1"
(string)FALSE //返回 ""
echo TRUE; //印出 "1"
echo FALSE; //什麼也不印!
匿名
1 個月前
表達式中的類型轉換會優先執行。
轉換會套用到值上,而不是表達式的結果。
範例

<?php

$string
= "777";

var_dump( $string === 777 ); // FALSE (假)
var_dump( (int) $string === 777 ); // TRUE (真)
var_dump( ( (int) $string ) === 777 ); // TRUE (真)
var_dump( (int) ( $string === 777 ) ); // 0
?>
To Top