将 PHP 数组转换为类变量
Posted
技术标签:
【中文标题】将 PHP 数组转换为类变量【英文标题】:Converting a PHP array to class variables 【发布时间】:2011-02-12 12:21:19 【问题描述】:简单的问题,如何将关联数组转换为类中的变量?我知道有演员要做(object) $myarray
或其他任何事情,但这会创建一个新的 stdClass 并且对我没有多大帮助。是否有任何简单的一两行方法可以使我的数组中的每个 $key => $value
对变成我班级的 $key = $value
变量?我觉得为此使用 foreach 循环不是很合乎逻辑,我最好将其转换为 stdClass 并将其存储在变量中,不是吗?
class MyClass
var $myvar; // I want variables like this, so they can be references as $this->myvar
function __construct($myarray)
// a function to put my array into variables
【问题讨论】:
我相信这个问题已经得到解答here。类本身内部的加载器方法似乎不是一个聪明的解决方案,因为您需要特别小心在构造函数内部抛出异常和错误处理。 【参考方案1】:这个简单的代码应该可以工作:
<?php
class MyClass
public function __construct(Array $properties=array())
foreach($properties as $key => $value)
$this->$key = $value;
?>
示例用法
$foo = new MyClass(array("hello" => "world"));
$foo->hello // => "world"
另外,这可能是更好的方法
<?php
class MyClass
private $_data;
public function __construct(Array $properties=array())
$this->_data = $properties;
// magic methods!
public function __set($property, $value)
return $this->_data[$property] = $value;
public function __get($property)
return array_key_exists($property, $this->_data)
? $this->_data[$property]
: null
;
?>
用法一样
// init
$foo = new MyClass(array("hello" => "world"));
$foo->hello; // => "world"
// set: this calls __set()
$foo->invader = "zim";
// get: this calls __get()
$foo->invader; // => "zim"
// attempt to get a data[key] that isn't set
$foo->invalid; // => null
【讨论】:
不要认为你需要 $this->$key = $value; 中的 声明 @AntonioCS,这不是必需的,但它肯定强调了对变量命名属性的访问。它还演示了当变量属性变得更复杂时,可以使用
;例如,$this->$this->foo('bar')->do_something();
真是两个不错的解决方案。我不知道那些神奇的方法,巧妙的技巧。
+1。还应该提到,除非您确保 __get 方法返回一个引用,否则使用带有数组的魔法方法可能会导致一些小问题(即 $this->myArray[] = $value;
将不起作用)
@Tobia 在第一种方法中,是的:property_exists
只有在类代码中明确定义了属性时才会返回 true。因此,您只需像往常一样定义属性,然后在构造函数的 foreach 循环中,在分配属性之前检查if (property_exists(self::class, $key))
。【参考方案2】:
最好的解决方案是让trait 带有静态函数fromArray
可用于数据加载:
trait FromArray
public static function fromArray(array $data = [])
foreach (get_object_vars($obj = new self) as $property => $default)
if (!array_key_exists($property, $data)) continue;
$obj->$property = $data[$property]; // assign value to object
return $obj;
然后你可以像这样使用这个特性:
class Example
use FromArray;
public $data;
public $prop;
然后你可以调用静态fromArray
函数来获取Example类的新实例:
$obj = Example::fromArray(['data' => 123, 'prop' => false]);
var_dump($obj);
我还有更复杂的版本,带有嵌套和值过滤https://github.com/OzzyCzech/fromArray
【讨论】:
不用get_object_vars($obj = new self
,你可以直接说get_class_vars(get_class($this))
——不需要创建一个虚拟对象。
@Meglio 实际上,它不是一个虚拟对象,它是设置属性后最终返回的实例。如果使用get_class($this)
或替代self::class
,则必须在循环之前创建一个实例。【参考方案3】:
如果你(像我一样)来这里寻找 array->class 的源代码生成器,我真的找不到任何源代码生成器,然后我想出了这个(正在进行的工作,没有经过很好的测试或任何东西, json_decode 返回数组。):
<?php
declare(strict_types = 1);
$json = <<<'JSON'
"object_kind":"push","event_name":"push","before":"657dbca6668a99012952c58e8c8072d338b48d20","after":"5ac3eda70dbb44bfdf98a3db87515864036db0f9","ref":"refs/heads/master","checkout_sha":"5ac3eda70dbb44bfdf98a3db87515864036db0f9","message":null,"user_id":805411,"user_name":"hanshenrik","user_email":"divinity76@gmail.com","user_avatar":"https://secure.gravatar.com/avatar/e3af2bd4b5604b0b661b5e6646544eba?s=80\u0026d=identicon","project_id":3498684,"project":"name":"gitlab_integration_tests","description":"","web_url":"https://gitlab.com/divinity76/gitlab_integration_tests","avatar_url":null,"git_ssh_url":"git@gitlab.com:divinity76/gitlab_integration_tests.git","git_http_url":"https://gitlab.com/divinity76/gitlab_integration_tests.git","namespace":"divinity76","visibility_level":0,"path_with_namespace":"divinity76/gitlab_integration_tests","default_branch":"master","homepage":"https://gitlab.com/divinity76/gitlab_integration_tests","url":"git@gitlab.com:divinity76/gitlab_integration_tests.git","ssh_url":"git@gitlab.com:divinity76/gitlab_integration_tests.git","http_url":"https://gitlab.com/divinity76/gitlab_integration_tests.git","commits":["id":"5ac3eda70dbb44bfdf98a3db87515864036db0f9","message":"dsf\n","timestamp":"2017-06-14T02:21:50+02:00","url":"https://gitlab.com/divinity76/gitlab_integration_tests/commit/5ac3eda70dbb44bfdf98a3db87515864036db0f9","author":"name":"hanshenrik","email":"divinity76@gmail.com","added":[],"modified":["gitlab_callback_page.php"],"removed":[]],"total_commits_count":1,"repository":"name":"gitlab_integration_tests","url":"git@gitlab.com:divinity76/gitlab_integration_tests.git","description":"","homepage":"https://gitlab.com/divinity76/gitlab_integration_tests","git_http_url":"https://gitlab.com/divinity76/gitlab_integration_tests.git","git_ssh_url":"git@gitlab.com:divinity76/gitlab_integration_tests.git","visibility_level":0
JSON;
$arr = json_decode ( $json, true );
var_dump ( array_to_class ( $arr ) );
/**
*
* @param array $arr
* @param string $top_class_name
*/
function array_to_class(array $arr, string $top_class_name = "TopClass"): string
$top_class_name = ucfirst ( $top_class_name );
$classes = array (); // deduplicated 'definition'=>true,array_keys();
$internal = function (array $arr, string $top_class_name) use (&$classes, &$internal)
$curr = 'Class ' . $top_class_name . ' ' . "\n";
foreach ( $arr as $key => $val )
$type = gettype ( $val );
if (is_array ( $val ))
$type = ucfirst ( ( string ) $key );
$classes [$internal ( $val, ( string ) $key )] = true;
$curr .= <<<FOO
/**
* @property $type \$$key
*/
FOO;
$curr .= "\n public $" . $key . ";\n";
$curr .= '';
$classes [$curr] = true;
;
$internal ( $arr, $top_class_name );
return implode ( "\n", array_keys ( $classes ) );
输出:
Class project
/**
* @property string $name
*/
public $name;
/**
* @property string $description
*/
public $description;
/**
* @property string $web_url
*/
public $web_url;
/**
* @property NULL $avatar_url
*/
public $avatar_url;
/**
* @property string $git_ssh_url
*/
public $git_ssh_url;
/**
* @property string $git_http_url
*/
public $git_http_url;
/**
* @property string $namespace
*/
public $namespace;
/**
* @property integer $visibility_level
*/
public $visibility_level;
/**
* @property string $path_with_namespace
*/
public $path_with_namespace;
/**
* @property string $default_branch
*/
public $default_branch;
/**
* @property string $homepage
*/
public $homepage;
/**
* @property string $url
*/
public $url;
/**
* @property string $ssh_url
*/
public $ssh_url;
/**
* @property string $http_url
*/
public $http_url;
Class author
/**
* @property string $name
*/
public $name;
/**
* @property string $email
*/
public $email;
Class added
Class modified
/**
* @property string $0
*/
public $0;
Class removed
Class 0
/**
* @property string $id
*/
public $id;
/**
* @property string $message
*/
public $message;
/**
* @property string $timestamp
*/
public $timestamp;
/**
* @property string $url
*/
public $url;
/**
* @property Author $author
*/
public $author;
/**
* @property Added $added
*/
public $added;
/**
* @property Modified $modified
*/
public $modified;
/**
* @property Removed $removed
*/
public $removed;
Class commits
/**
* @property 0 $0
*/
public $0;
Class repository
/**
* @property string $name
*/
public $name;
/**
* @property string $url
*/
public $url;
/**
* @property string $description
*/
public $description;
/**
* @property string $homepage
*/
public $homepage;
/**
* @property string $git_http_url
*/
public $git_http_url;
/**
* @property string $git_ssh_url
*/
public $git_ssh_url;
/**
* @property integer $visibility_level
*/
public $visibility_level;
Class TopClass
/**
* @property string $object_kind
*/
public $object_kind;
/**
* @property string $event_name
*/
public $event_name;
/**
* @property string $before
*/
public $before;
/**
* @property string $after
*/
public $after;
/**
* @property string $ref
*/
public $ref;
/**
* @property string $checkout_sha
*/
public $checkout_sha;
/**
* @property NULL $message
*/
public $message;
/**
* @property integer $user_id
*/
public $user_id;
/**
* @property string $user_name
*/
public $user_name;
/**
* @property string $user_email
*/
public $user_email;
/**
* @property string $user_avatar
*/
public $user_avatar;
/**
* @property integer $project_id
*/
public $project_id;
/**
* @property Project $project
*/
public $project;
/**
* @property Commits $commits
*/
public $commits;
/**
* @property integer $total_commits_count
*/
public $total_commits_count;
/**
* @property Repository $repository
*/
public $repository;
【讨论】:
【参考方案4】:这是另一个使用PDOStatement::fetchObject
的解决方案,虽然它有点小技巧。
$array = array('property1' => 'value1', 'property2' => 'value2');
$className = 'MyClass';
$pdo = new PDO('sqlite::memory:'); // we don't actually need sqlite; any PDO connection will do
$select = 'SELECT ? AS property1, ? AS property2'; // this could also be built from the array keys
$statement = $pdo->prepare($select);
// this last part can also be re-used in a loop
$statement->execute(array_values($array));
$myObject = $statement->fetchObject($className);
【讨论】:
【参考方案5】:定义一个静态方法来转换从数组中获取实例。最好,为它定义一个接口。这是声明性的,不会污染构造函数,允许您设置私有属性并仍然实现反射无法实现的自定义逻辑。如果您想要一个通用的解决方案,请定义一个特征并在您的类中使用它。
class Test implements ContructableFromArray
private $property;
public static function fromArray(array $array)
$instance = new self();
$instance->property = $array['property'];
return $instance;
interface ConstructableFromArray
public static function fromArray(array $array);
【讨论】:
如果您的业务逻辑不需要接口,请不要创建接口。这是矫枉过正。【参考方案6】:如果要将嵌套数组转换为对象,请使用以下代码:
class ToObject
private $_data;
public function __construct(array $data)
$this->setData($data);
/**
* @return array
*/
public function getData()
return $this->_data;
/**
* @param array $data
*/
public function setData(array $data)
$this->_data = $data;
return $this;
public function __call($property, $args)
// NOTE: change lcfirst if you need (ucfirst/...) or put all together
$property = lcfirst(str_replace('get', '', $property));
if (array_key_exists($property, $this->_data))
if (is_array($this->_data[$property]))
return new self($this->_data[$property]);
return $this->_data[$property];
return null;
那么你可以这样使用:
$array = [
'first' => '1.1',
'second' => [
'first' => '2.1',
'second' => '2.2',
'third' => [
'first' => '2.3.1'
]
]
];
$object = new ToObject($array);
$object->getFirst(); // returns 1.1
$object->getSecond()->getFirst(); // returns 2.1
$object->getSecond()->getData(); // returns second array
$object->getSecond()->getThird()->getFirst(); // returns 2.3.1
【讨论】:
以上是关于将 PHP 数组转换为类变量的主要内容,如果未能解决你的问题,请参考以下文章