CakeFest 2024: The Official CakePHP Conference

类型转换

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

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

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

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

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

Numeric contexts

This is the context when using an arithmetical operator.

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

String contexts

This is the context when using echo, print, string interpolation, or the string concatenation operator.

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

Logical contexts

This is the context when using conditional statements, the ternary operator, or a logical operator.

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

Integral and string contexts

This is the context when using bitwise operators.

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

Comparative contexts

This is the context when using a comparison operator.

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

Function contexts

This is the context when a value is passed to a typed parameter, property, or returned from a function which declares a return type.

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

警告

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

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

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

使用联合类型的强制类型

When strict_types is not enabled, scalar type declarations are subject to limited implicit type coercions. 如果值的精确类型不是联合的一部分,然后会按照以下优先顺序选择目标类型:

  1. int
  2. float
  3. string
  4. bool
If the type exists in the union and the value can be coerced to the type under PHP's existing type-checking semantics, then the type is chosen. Otherwise, the next type is tried.

警告

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

注意:

Types that are not part of the above preference list are not eligible targets for implicit coercion. In particular no implicit coercions to the null, false, and true types occur.

示例 #1 Example of types being coerced into a type part of the union

<?php
// int|string
42 --> 42 // exact type
"42" --> "42" // exact type
new ObjectWithToString --> "Result of __toString()"
// object never compatible with int, fall back to string
42.0 --> 42 // float compatible with int
42.1 --> 42 // float compatible with int
1e100 --> "1.0E+100" // float too large for int type, fall back to string
INF --> "INF" // float too large for int type, fall back to string
true --> 1 // bool compatible with int
[] --> TypeError // array not compatible with int or string

// int|float|bool
"45" --> 45 // int numeric string
"45.0" --> 45.0 // float numeric string

"45X" --> true // not numeric string, fall back to bool
"" --> false // not numeric string, fall back to bool
"X" --> true // not numeric string, fall back to bool
[] --> TypeError // array not compatible with int, float or bool
?>

类型转换

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

<?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
?>
请查看章节标题为存取和修改字符串中的字符获取更多信息。

add a note

User Contributed Notes 7 notes

up
66
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
27
fardelian
10 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
11
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
11
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
11
rmirabelle
13 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
16
Anonymous
21 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
12
ieee at REMOVE dot bk dot ru
11 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;
?>
To Top