Converting a PHP array to class variables
Simple question, how do I convert an associative array to variables in a class? I know there is casting to do an (object) $myarray
or whatever it is, but that will create a new stdClass and doesn't help me much. Are there any easy one or two line methods to make each $key => $value
pair in my array into a $key = $value
variable for my class? I don't find it very logical to use a foreach loop for this, I'd be better off just converting it to a stdClass and storing that in a variable, wouldn't I?
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 开发者_StackOverflowarray into variables
}
}
This simple code should work:
<?php
class MyClass {
public function __construct(Array $properties=array()){
foreach($properties as $key => $value){
$this->{$key} = $value;
}
}
}
?>
Example usage
$foo = new MyClass(array("hello" => "world"));
$foo->hello // => "world"
Alternatively, this might be a better approach
<?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
;
}
}
?>
Usage is the same
// 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
Best solution is to have trait with static function fromArray
that can be used for data loading:
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;
}
}
Then you can use this trait like that:
class Example {
use FromArray;
public $data;
public $prop;
}
Then you can call static fromArray
function to get new instance of Example class:
$obj = Example::fromArray(['data' => 123, 'prop' => false]);
var_dump($obj);
I also have much more sophisticated version with nesting and value filtering https://github.com/OzzyCzech/fromArray
if you (like me) came here looking for a source code generator for array->class, i couldn't really find any, and then i came up with this (a work in progress, not well tested or anything, json_decode returns the array.):
<?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 ) );
}
output:
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;
}
Here's another solution using PDOStatement::fetchObject
, though it is a bit of a hack.
$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);
Define a static method to convert get an instance from an array. Best, define an interface for it. This is declarative, does not pollute the constructor, allows you to set private properties and still implement custom logic that would not be possible with Reflection. If you want a generic solution, define a trait and use it in your classes.
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);
}
If you want to cast nested array to object use this code:
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;
}
}
Then you can use like this:
$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
Just use the php spread operator
class Whatever
{
public function __construct(public int $something) {}
public static function fromArray(array $data)
{
return new self(...$data);
}
}
$data = ['something' => 1];
$instance = Whatever::fromArray($data);
$instance->something; // equals 1
精彩评论