类型转换

PHP 在变量声明时不需要定义类型。在这种情况下,变量的类型由存储的值决定。也就是说,如果 string 赋值给 $var,然后 $var 的类型就是 string。之后将 int 值赋值给 $var,它将是 int 类型。

PHP 可能会尝试在某些上下文中自动将值转换为另一种类型。不同的上下文有:

  • Numeric
  • String
  • Logical
  • Integral and string
  • Comparative
  • Function

注意: 当值需要解释为不同类型时,值本身会改变类型。

强制将变量当做某种变量来求值,参见类型转换一节。要更改变量的类型,请参阅 settype() 函数。

数字上下文

使用算术运算符时的上下文。

在这种情况下,如果任一运算对象是 float(或者不能解释为 int),则两个运算对象都将解释为 float,结果也将是 float。否则,运算对象将解释为 int,结果也将是 int。自 PHP 8.0.0 起,如果无法解释其中一个运算对象,则会抛出 TypeError

字符串上下文

使用 echoprint字符串插值或者字符串连接运算符时的上下文。

这种情况下,值将会解释为 string。如果值无法解释,那么会抛出 TypeError。在 PHP 7.4.0 之前,会引发 E_RECOVERABLE_ERROR

逻辑上下文

使用条件语句、三元运算符逻辑运算符时的上下文。

在这种情况下,值将会解释为 bool

整数和字符串上下文

使用位运算符时的上下文。

在这种情况下,如果所有的运算对象都是 string,则结果也将是 string。否则运算对象将解释为 int,结果也将是 int。如果其中一个运算对象无法解释,则会抛出 TypeError

比较上下文

使用比较运算符时的上下文。

在此上下文中发生的类型转换在比较多种类型中进行了说明。

函数上下文

将值传递给已声明类型的参数、属性,或从声明了返回类型的函数返回值时的上下文。

在此上下文中,值必须是类型值。但存在两个例外,第一个是如果值为 int,但声明的类型是 float,然后整数会转换为浮点数。第二个是如果声明的类型是 scalar 类型,值可转换为标量类型,并且强制类型模式处于活动状态(默认),值会转换为可接受的标量值。参见下文查看有关此行为的描述。

警告

内部函数自动将 null 转换为标量类型,此行为自 PHP 8.1.0 起弃用

使用简单类型声明的强制类型

  • bool 类型声明:值将解释为 bool
  • int 类型声明:如果明确定义转换,则值将解释为 int。例如,字符串是数字
  • float 类型声明:如果明确定义转换,则值将解释为 float。例如,字符串是数字
  • string 类型声明:值将解释为 string

使用联合类型的强制类型

当未启用 strict_types 时,声明的标量类型会受到有限的隐式类型转换的影响。如果值的精确类型不是联合的一部分,然后会按照以下优先顺序选择目标类型:

  1. int
  2. float
  3. string
  4. bool
如果类型存在于 union 类型中,并且值可以根据 PHP 现有的类型检查语义转换为此类型,则选择该类型。否则,尝试下一个类型

警告

有个例外,如果值是字符串,并且 int 和 float 都是联合类型的一部分,首选类型则通过现有的数字字符串语义决定。例如 "42" 选择 int"42.0" 选择 float

注意:

不属于上述优先级列表的类型不会进行隐式转换。特别是,不会出现对 nullfalsetrue 类型的隐式转换。

示例 #1 类型转换为 union 类型中的一个的示例

<?php
// int|string
42 --> 42 // 具体类型
"42" --> "42" // 具体类型
new ObjectWithToString --> "Result of __toString()"
// 对象绝不会兼容 int,回退到 string
42.0 --> 42 // int 兼容 float
42.1 --> 42 // int 兼容 float
1e100 --> "1.0E+100" // float 对于 int 类型来说太大了,回退为 string
INF --> "INF" // float 对于 int 类型来说太大了,回退为 string
true --> 1 // int 兼容 bool
[] --> TypeError // int 或 string 不兼容 array

// int|float|bool
"45" --> 45 // int 数字 string
"45.0" --> 45.0 // float 数字 string

"45X" --> true // 不是 numeric string,回退为 bool
"" --> false // 不是 numeric string,回退为 bool
"X" --> true // 不是 numeric string,回退为 bool
[] --> TypeError // int、float 或 bool 不兼容 array
?>

类型转换

类型转换通过在值前面的括号中写入类型来将值转换指定的类型。

<?php
$foo
= 10; // $foo 是 int
$bar = (bool) $foo; // $bar 是 bool
?>

允许的转换是:

  • (int) ——转换为 int
  • (bool) ——转换为 bool
  • (float) ——转换为 float
  • (string) ——转换为 string
  • (array) ——转换为 array
  • (object) ——转换为 object
  • (unset) ——转换为 NULL

注意:

(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;
?>

将文字 string 和变量转换为二进制 string

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

注意: 除了将变量转换为 string 之外,还可以将变量放在双引号内。

<?php
$foo
= 10; // $foo 是 int
$str = "$foo"; // $str 是 string
$fst = (string) $foo; // $fst 也是 string

// 打印出 "they are the same"
if ($fst === $str) {
echo
"they are the same";
}
?>

有时在类型之间转换时确切地会发生什么可能不是很明显。更多信息见如下不分:

注意: 因为 PHP 的 string 支持使用与 array 索引相同的语法,通过偏移量进行索引,所以以下示例适用于所有 PHP 版本:

<?php
$a
= 'car'; // $a 是 string
$a[0] = 'b'; // $a 依然是 string
echo $a; // bar
?>
请查看章节标题为存取和修改字符串中的字符获取更多信息。

添加备注

用户贡献的备注 8 notes

up
71
Raja
19 years ago
Uneven division of an integer variable by another integer variable will result in a float by automatic conversion -- you do not have to cast the variables to floats in order to avoid integer truncation (as you would in C, for example):

$dividend = 2;
$divisor = 3;
$quotient = $dividend/$divisor;
print $quotient; // 0.66666666666667
up
14
Anonymous
3 years ago
Cast operators have a very high precedence, for example (int)$a/$b is evaluated as ((int)$a)/$b, not as (int)($a/$b) [which would be like intdiv($a,$b) if both $a and $b are integers].
The only exceptions (as of PHP 8.0) are the exponentiation operator ** [i.e. (int)$a**$b is evaluated as (int)($a**$b) rather than ((int)$a)**$b] and the special access/invocation operators ->, ::, [] and () [i.e. in each of (int)$a->$b, (int)$a::$b, (int)$a[$b] and (int)$a($b), the cast is performed last on the result of the variable expression].
up
27
fardelian
11 years ago
Casting objects to arrays is a pain. Example:

<?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);

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

?>

Yes, that looks like an array with two keys with the same name and it looks like the protected field was prepended with an asterisk. But that's not true:

<?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
*/

?>

The char codes show that the protected keys are prepended with '\0*\0' and private keys are prepended with '\0'.__CLASS__.'\0' so be careful when playing around with this.
up
16
miracle at 1oo-percent dot de
18 years ago
If you want to convert a string automatically to float or integer (e.g. "0.234" to float and "123" to int), simply add 0 to the string - PHP will do the rest.

e.g.

$val = 0 + "1.234";
(type of $val is float now)

$val = 0 + "123";
(type of $val is integer now)
up
13
rmirabelle
14 years ago
The object casting methods presented here do not take into account the class hierarchy of the class you're trying to cast your object into.

/**
* Convert an object to a specific class.
* @param object $object
* @param string $class_name The class to cast the object to
* @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);
/**
* The new object is of the correct type but
* is not fully initialized throughout its graph.
* To get the full object graph (including parent
* class data, we need to create a new instance of
* the specified class and then assign the new
* properties to it.
*/
$graph = new $class_name;
foreach($new_object as $prop => $val) {
$graph->$prop = $val;
}
return $graph;
} else {
throw new CoreException(false, "could not find class $class_name for casting in DB::cast");
return false;
}
}
up
18
ieee at REMOVE dot bk dot ru
12 years ago
There are some shorter and faster (at least on my machine) ways to perform a type cast.
<?php
$string
='12345.678';
$float=+$string;
$integer=0|$string;
$boolean=!!$string;
?>
up
18
Anonymous
22 years ago
Printing or echoing a FALSE boolean value or a NULL value results in an empty string:
(string)TRUE //returns "1"
(string)FALSE //returns ""
echo TRUE; //prints "1"
echo FALSE; //prints nothing!
up
1
Anonymous
18 days ago
Type casting in expressions is executed first.
The casting is assigned to the value, not to the expression result.
Examples:

<?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