php 将对象转换为数组 - 调用任何魔术方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11121613/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Casting object to array - any magic method being called?
提问by Majql
I have an object of class Foo:
我有一个 Foo 类的对象:
class Foo extends Bar {
protected $a;
protected $b;
}
$obj = new Foo();
What I want (and have) to do is cast this object to an array, like this:
我想要(并且必须)做的是将此对象强制转换为数组,如下所示:
$arr = (array)$obj;
Is there any magic (or not magic :)) method that is being called at this moment? Or is there any other way to intercept it? I know I can write a simple method, eg. asArray()in Foo, but I'm looking for some more "native" PHP ways.
此时是否有任何魔法(或不是魔法 :))方法被调用?或者有什么其他方法可以拦截?我知道我可以写一个简单的方法,例如。asArray()在 Foo 中,但我正在寻找一些更“本机”的 PHP 方式。
采纳答案by Explosion Pills
You can have the class implement the ArrayAccessinterface. This will allow you to treat the object like an array without casting and you get total control over how the members are used.
您可以让类实现ArrayAccess接口。这将允许您将对象视为数组而不进行强制转换,并且您可以完全控制成员的使用方式。
回答by tacone
No
不
There is no __toArraymagic method in PHP. An enhancement proposal has been rejectedin 2006with the following answer:
__toArrayPHP 中没有魔法方法。2006 年,一项改进提案被拒绝,答复如下:
[2006-08-20 11:12 UTC] [email protected]
Why not simply have a method asArray() maybe even as par of an interface:
interface ArrayConversion { function asArray(); }
See, we have __toString as it is supported in language constructs like echo, print and other internal functions. But we decided against an autoconversion for arrays already. So itwill never be supported in any language construct. That said there is no needed for this and nothing you would win against the above interface. In fact you would make it php more complex because you'd add just one more magic feature.
[2006-08-20 11:12 UTC] [email protected]
为什么不简单地将方法 asArray() 甚至作为接口的标准:
interface ArrayConversion { function asArray(); }
看,我们有 __toString 因为它在诸如 echo、print 和其他内部函数之类的语言结构中受支持。但是我们已经决定不对数组进行自动转换。所以它永远不会被任何语言结构支持。也就是说没有必要这样做,并且您不会在上述界面中获胜。事实上,您会使其 php 变得更加复杂,因为您只需要再添加一项神奇的功能。
It is thus very unlikely that it will be implemented in any future release (which is a pity, if you ask me).
因此,它不太可能在未来的任何版本中实现(如果你问我,这很遗憾)。
回答by Boris Guéry
Sadly no, casting to array doesn't trigger any magic method like it is done with:
遗憾的是,不,转换为数组不会触发任何魔法方法,就像它完成的那样:
$s = (string)$obj;
which triggers __toString()method and which you can override.
哪个触发__toString()方法,您可以覆盖哪个。
However, you may write a custom toArray()method.
但是,您可以编写自定义toArray()方法。
You may also be interested in the Serializableinterface which allows you to write custom serializer strategy.
您可能还对Serializable允许您编写自定义序列化程序策略的接口感兴趣。
回答by Nazariy
Not sure if this question still relevant, but php has builtin ArrayObjectclass, that allows to treat object as array and can be handy when used as container for database record or collection.
不确定这个问题是否仍然相关,但 php 有内置的ArrayObject类,它允许将对象视为数组,并且在用作数据库记录或集合的容器时会很方便。
It might be not a best practice in regards to strict types, but it allows to treat object as array and both statements are valid.
这可能不是严格类型的最佳实践,但它允许将对象视为数组并且两个语句都是有效的。
$obj = new ArrayObject(['a' => 'alpha']);
var_dump($obj['a']); //alpha
var_dump($obj->getOffset('a'));//alpha
However you need to keep in mind behaviour of ArrayObject
但是你需要记住的行为 ArrayObject
$obj = new ArrayObject(['a' => 'alpha']);
//Access Property
var_dump($obj['a']); //alpha
var_dump($obj->offsetGet('a'));//alpha
var_dump($obj->a); //null Notice: Undefined property: ArrayObject::$a
//Serialization
var_dump(serialize($obj));// string 'C:11:"ArrayObject":41:{x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}}' (length=65)
var_dump($obj->serialize());// string 'x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}'
var_dump(serialize($obj) === $obj->serialize());// false !!!
//Setting Properties
$obj['b'] = 'beta'; //OK
$obj->c = 'gamma'; //value becomes object property!!!
var_dump($obj);
/* OBJECT DUMP
object(ArrayObject)[13]
public 'c' => string 'gamma' (length=5)
private 'storage' =>
array (size=2)
'a' => string 'alpha' (length=5)
'b' => string 'beta' (length=4)
*/
//Property validation as array
var_dump(isset($obj['a']));//true
var_dump(isset($obj['b']));//true
var_dump(isset($obj['c']));//false
//Property validation as object
var_dump(isset($obj->a));//false
var_dump(isset($obj->b));//false
var_dump(isset($obj->c));//true
//Typecasting
var_dump((array)$obj);
/*
array (size=2)
'a' => string 'alpha' (length=5)
'b' => string 'beta' (length=4)
*/
//var_dump((string)$obj);// Catchable fatal error: Object of class ArrayObject could not be converted to string
ArrayObject accepts two flags ArrayObject::STD_PROP_LISTas default and ArrayObject::ARRAY_AS_PROPSas alternative.
ArrayObject 接受两个标志ArrayObject::STD_PROP_LIST作为默认标志和ArrayObject::ARRAY_AS_PROPS替代标志。
This would change behaviour for reading values but does not support setting new properties in that way, here is example:
这会改变读取值的行为,但不支持以这种方式设置新属性,示例如下:
$obj = new ArrayObject(['a' => 'alpha'], ArrayObject::ARRAY_AS_PROPS);
//Access Property
var_dump($obj['a']); //alpha
var_dump($obj->offsetGet('a'));//alpha
var_dump($obj->a);//alpha
//Serialization
var_dump(serialize($obj));// string 'C:11:"ArrayObject":41:{x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}}' (length=65)
var_dump($obj->serialize());// string 'x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}'
var_dump(serialize($obj) === $obj->serialize());// false !!!
//Setting Properties
$obj['b'] = 'beta'; //OK
$obj->c = 'gamma'; //OK
var_dump($obj);
/* OBJECT DUMP
object(ArrayObject)[14]
private 'storage' =>
array (size=3)
'a' => string 'alpha' (length=5)
'b' => string 'beta' (length=4)
'c' => string 'gamma' (length=5)
*/
//Property validation as array
var_dump(isset($obj['a']));//true
var_dump(isset($obj['b']));//true
var_dump(isset($obj['c']));//false !!!
//Property validation as object
var_dump(isset($obj->a));//true
var_dump(isset($obj->b));//true
var_dump(isset($obj->c));//true
//Typecasting
var_dump((array)$obj);
/*
array (size=2)
'a' => string 'alpha' (length=5)
'b' => string 'beta' (length=4)
*/
To make this behaviour more consistent you would have to extend this class and implement magic methods __get(), __set(), __isset()and __unset().
为了使这种行为更加一致,你就必须扩展这个类,并实现魔术方法__get(),__set(),__isset()和__unset()。
Another tricky part is serialization, default method serializewould return you a copy serialized $storagevariable instead of object itself, as workaround to return serialized copy of instance you can implement default serialization in __toStringmethod, this way it's behave correctly.
另一个棘手的部分是序列化,默认方法serialize将返回一个副本序列化$storage变量而不是对象本身,作为返回实例序列化副本的解决方法,您可以在__toString方法中实现默认序列化,这样它的行为就正确了。
class FooObject extends ArrayObject
{
public function __get($index)
{
if ($this->offsetExists($index)) {
return $this->offsetGet($index);
} else {
throw new UnexpectedValueException('Undefined key ' . $index);
}
}
public function __set($index, $value)
{
$this->offsetSet($index, $value);
return $this;
}
public function __isset($index)
{
return $this->offsetExists($index);
}
public function __unset($index)
{
return $this->offsetUnset($index);
}
public function __toString()
{
return serialize($this);
}
}
Example of usage
使用示例
$obj2 = new FooObject(['a' => 'alpha']);
//Access Property
var_dump($obj2['a']); //alpha
var_dump($obj2->offsetGet('a'));//alpha
var_dump($obj2->a); //alpha
//Serialization
var_dump(serialize($obj));// string 'C:11:"ArrayObject":41:{x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}}' (length=65)
var_dump($obj->serialize());// string 'x:i:0;a:1:{s:1:"a";s:5:"alpha";};m:a:0:{}'
var_dump(serialize($obj) === $obj->serialize());// false !!!
//Setting Properties
$obj2['b'] = 'beta'; //OK
$obj2->c = 'gamma'; //OK
var_dump($obj2);
/* OBJECT DUMP
object(FooObject)[14]
private 'storage' (ArrayObject) =>
array (size=3)
'a' => string 'alpha' (length=5)
'b' => string 'beta' (length=4)
'c' => string 'gamma' (length=5)
*/
//Property validation as array
var_dump(isset($obj2['a']));//true
var_dump(isset($obj2['b']));//true
var_dump(isset($obj2['c']));//true
//Property validation as object
var_dump(isset($obj2->a));//true
var_dump(isset($obj2->b));//true
var_dump(isset($obj2->c));//true
//Typecasting
var_dump((array)$obj2);
/*
array (size=3)
'a' => string 'alpha' (length=5)
'b' => string 'beta' (length=4)
'c' => string 'gamma' (length=5)
*/
回答by hessodreamy
One way to do this, without changing the original class definition is to use reflection. This allows to you examine the class's properties at runtime.
在不更改原始类定义的情况下执行此操作的一种方法是使用反射。这允许您在运行时检查类的属性。
Taken from the manual: http://www.php.net/manual/en/reflectionclass.getproperties.php
取自手册:http: //www.php.net/manual/en/reflectionclass.getproperties.php
<?php
class Foo {
public $foo = 1;
protected $bar = 2;
private $baz = 3;
}
$foo = new Foo();
$reflect = new ReflectionClass($foo);
$props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED);
foreach ($props as $prop) {
print $prop->getName() . "\n";
}
var_dump($props);
?>
The above example will output something similar to:
foo
bar
array(2) {
[0]=>
object(ReflectionProperty)#3 (2) {
["name"]=>
string(3) "foo"
["class"]=>
string(3) "Foo"
}
[1]=>
object(ReflectionProperty)#4 (2) {
["name"]=>
string(3) "bar"
["class"]=>
string(3) "Foo"
}
}
回答by Aghanim
You can use get_object_vars($yourObject) that will return an associative array of all property names/values accessible from the context.
您可以使用 get_object_vars($yourObject) 返回一个关联数组,该数组包含可从上下文访问的所有属性名称/值。
See http://php.net/manual/en/function.get-object-vars.php
见http://php.net/manual/en/function.get-object-vars.php
A you want to access protected or private properties, my advice would be to extend ArrayObject, that implements the method getArrayCopy()
如果您想访问受保护或私有属性,我的建议是扩展 ArrayObject,它实现了 getArrayCopy() 方法

