提问人:Mark G 提问时间:2/25/2023 更新时间:2/26/2023 访问量:260
为什么一个对象可以被强制转换为数组,但在 PHP 中不能作为数组参数传递?
Why can an object be cast to an array, but cannot be passed as an array argument in PHP?
问:
如果我有一个在ArrayObject中表示的数组,如下所示:
$arrObj = new ArrayObject([
'foo' => 1,
'bar' => 2,
]);
然后我可以舒适地投射它:
print_r((array)$array);
// output is as expected
但是我不能将其作为类型化为数组的参数传递:
function castTest(array $array)
{
}
castTest($arrObj);
// TypeError: castTest(): Argument #1 ($array) must be of type array, ArrayObject given
这是故意的吗?合意?PHP 中是否有任何例外情况可以自动将对象转换为数组?
它适用于字符串对象,例如,实现__toString:
class Str
{
private string $string;
public function __construct(string $string)
{
$this->string = $string;
}
public function __toString()
{
return $this->string;
}
}
function castTest(string $string)
{
echo $string;
}
$str = new Str('hello, world');
castTest($str); // outputs: hello, world
答:
是的,这是故意的。ArrayObject 的行为可能类似于数组,但实际上并不是数组。PHP 在函数参数中强制执行严格的类型。如果参数定义为数组,则它只接受数组。你观察到的方法的行为是不同的,因为当一个对象在字符串上下文中使用时,如果定义了该方法,PHP 会自动调用该方法。但是,此行为不适用于数组或其他非字符串类型。__toString
__toString
您可以使用以下方法将 ArrayObject 转换为 ArraygetArrayCopy()
castTest($arrObj->getArrayCopy());
这是因为它是一种不同的类型,并且参数类型检查很严格。数组是一种类型。is 和 “object” 类型(虽然没有类型,但它仍然是 PHP 中一个单独的变量类型)。这也是因为 PHP 没有标量对象。它们是在后台表示标量值的对象。例如,如果创建一个变量,则具有标量对象的语言将透明地实例化对象。过去曾多次向 PHP 提出过这样的建议,但不太可能很快添加。array
ArrayObject
Object
string
String
但是,可以通过更改参数的类型限制来允许数组对象与数组一起传递。PHP 8 引入了使用竖线字符的联合类型。您可以通过添加 ArrayAccess
接口来允许能够像数组一样访问对象:
$arrObj = new ArrayObject([
'foo' => 1,
'bar' => 2,
]);
function castTest(array|ArrayAccess $array)
{
}
castTest($arrObj); // No problem here
类型限制意味着“只允许类型或对象类型的变量”。array|ArrayAccess
array
ArrayAccess
如果您使用的是旧版本的 PHP(7 或更早版本),您的两个选项是将对象转换为数组(请记住,它不再是函数中的对象,而完全是一个单独的数组,这可能会产生影响,具体取决于数据的处理方式),或者检查函数本身中的类型。以下是一些示例:
- 将对象转换为数组(例如,将对象的值复制到新数组中):
function castTest(array $array)
{
}
castTest((array) $arrObj); // No problem here... ?
castTest($arrObj->getArrayCopy()); // Same as above, just using a method instead of type casting.
- 检查函数中的类型:
function castTest($array)
{
if(!is_array($array) && !($array instanceof ArrayAccess)) {
throw new InvalidArgumentException(
'Array or ArrayAccess object type expected, ' .
(is_object($array) ?
('object of type ' . get_class($array)) :
get_type($array)) . ' provided.'
);
}
}
castTest($arrObj); // If something other than an array or object with `ArrayAccess` is passed to the function, an exception is thrown.
评论
__toString
__toArray
__toInt
__toCallable
castTest((array)$arrObj);
应该工作得很好。当你这样做时,它不会改变。为此,您需要再次将其分配为(array)$arrObj
$arrObj
$arrObj = (array)$arrObj
string
__toString
Stringable