Сделать массив объектом php
// Before php 5.4
$array = array(1,2,3);
// since php 5.4 , short syntax
$array = [1,2,3];
// I recommend using the short syntax if you have php version >= 5.4
Used to creating arrays like this in Perl?
Looks like we need the range() function in PHP:
$array = array_merge (array( ‘All’ ), range ( ‘A’ , ‘Z’ ));
?>
You don’t need to array_merge if it’s just one range:
There is another kind of array (php>= 5.3.0) produced by
$array = new SplFixedArray(5);
Standard arrays, as documented here, are marvellously flexible and, due to the underlying hashtable, extremely fast for certain kinds of lookup operation.
Supposing a large string-keyed array
$arr=[‘string1’=>$data1, ‘string2’=>$data2 etc. ]
when getting the keyed data with
php does *not* have to search through the array comparing each key string to the given key (‘string1’) one by one, which could take a long time with a large array. Instead the hashtable means that php takes the given key string and computes from it the memory location of the keyed data, and then instantly retrieves the data. Marvellous! And so quick. And no need to know anything about hashtables as it’s all hidden away.
However, there is a lot of overhead in that. It uses lots of memory, as hashtables tend to (also nearly doubling on a 64bit server), and should be significantly slower for integer keyed arrays than old-fashioned (non-hashtable) integer-keyed arrays. For that see more on SplFixedArray :
Unlike a standard php (hashtabled) array, if you lookup by integer then the integer itself denotes the memory location of the data, no hashtable computation on the integer key needed. This is much quicker. It’s also quicker to build the array compared to the complex operations needed for hashtables. And it uses a lot less memory as there is no hashtable data structure. This is really an optimisation decision, but in some cases of large integer keyed arrays it may significantly reduce server memory and increase performance (including the avoiding of expensive memory deallocation of hashtable arrays at the exiting of the script).
When creating arrays , if we have an element with the same value as another element from the same array, we would expect PHP instead of creating new zval container to increase the refcount and point the duplicate symbol to the same zval. This is true except for value type integer.
Example:
$arr = [‘bebe’ => ‘Bob’, ‘age’ => 23, ‘too’ => 23 ];
xdebug_debug_zval( ‘arr’ );
(refcount=2, is_ref=0)
array (size=3)
‘bebe’ => (refcount=1, is_ref=0)string ‘Bob’ (length=3)
‘age’ => (refcount=0, is_ref=0)int 23
‘too’ => (refcount=0, is_ref=0)int 23
but :
$arr = [‘bebe’ => ‘Bob’, ‘age’ => 23, ‘too’ => ’23’ ];
xdebug_debug_zval( ‘arr’ );
(refcount=2, is_ref=0)
array (size=3)
‘bebe’ => (refcount=1, is_ref=0)string ‘Bob’ (length=3)
‘age’ => (refcount=0, is_ref=0)int 23
‘too’ => (refcount=1, is_ref=0)string ’23’ (length=2)
or :
$arr = [‘bebe’ => ‘Bob’, ‘age’ => [1,2], ‘too’ => [1,2] ];
xdebug_debug_zval( ‘arr’ );
(refcount=2, is_ref=0)
array (size=3)
‘bebe’ => (refcount=1, is_ref=0)string ‘Bob’ (length=3)
‘age’ => (refcount=2, is_ref=0)
array (size=2)
0 => (refcount=0, is_ref=0)int 1
1 => (refcount=0, is_ref=0)int 2
‘too’ => (refcount=2, is_ref=0)
array (size=2)
0 => (refcount=0, is_ref=0)int 1
1 => (refcount=0, is_ref=0)int 2
This function makes (assoc.) array creation much easier:
function arr (. $array )< return $array ; >
?>
It allows for short syntax like:
$arr = arr ( x : 1 , y : 2 , z : 3 );
?>
Instead of:
$arr = [ «x» => 1 , «y» => 2 , «z» => 3 ];
// or
$arr2 = array( «x» => 1 , «y» => 2 , «z» => 3 );
?>
Sadly PHP 8.2 doesn’t support this named arguments in the «array» function/language construct.
Делаем из массивов объекты
PHP содержит очень мощный инструмент — массивы. Половина функций в PHP возвращает результат как ассоциативные массивы. При работе с такими функциями легко допустить ошибки в именовании ключей массива. Понятно что для опытного разработчика это не составляет проблем, но для начинающих это частенько может стать головной болью, особенно если мы получаем огромный json или просто правим legasylegacy код, ну а для не программистов… (таких как я) может послужить генератором говнострашного кода.
Тут приведу некий трюк, который позволяет использовать массив как объект/коллекцию. Возможно кому то это покажется глупым, а кому то даст идеи для применения.
Сразу оговорюсь что реализация рабочая для PHPStorm, в других IDE нужно вам проверять.
Часть примеров будет взята с потолка, часть будет взята из Instagram api.
Примеры
Пример 1. Работаем с данными формы.
| |
При отправке получаем $_POST. Мне всегда не нравилось такое использование (проверку существования ключей опускаю)
$id = $_POST[‘id];
Куда интереснее использовать все возможности нашего IDE и знать за ранее о переменных в нашем POST.
Создаем класс для формы:
/* @property $id string*/ /* @property $secret string */ /* @property $tag string*/ /* @property $subscribe string value from MyForm::const*/ class MyForm extends Post
Ну и результат использования такого «класса»
Сразу видно с чем имеем дело.
Пример 2. Работаем с сессиями.
/* @property $var1 string */ /* @property $var2 string */ /* @property $var3 string */ class MySession extends Session < function __construct() < parent::__construct('mySession'); >>
Класс для сессий (код ArrayClass будет в конце):
class Session extends ArrayClass < function __construct($arrayName = 'session') < if(!isset($_SESSION[$arrayName])) $_SESSION[$arrayName] = array(); parent::__construct($_SESSION[$arrayName]); >public static function init() < session_start(); >>
Это нам позволяет спокойно работать так:
$s = new MySession();
$s->var1 = 10;
Всё просто и прозрачно.
Пример 3. Instagram, json и сложные массивы
$response = file_get_contents("https://api.instagram.com/v1/tags/instaprint/media/recent?access_token=14135310***************************9f2a26b8a"); $r = new Response(json_decode($response, true)); //$r = new Response($response); также сработает $body = "Data count \n"; $tags = $r->data; $data = new TagData($r->data->get(0)); $url = $data->images->standard_resolution->url; $body.= $data->id; $body.= "Image0 url: ".$url; $body.= '';
/** * Class Response * @package instagram * * @property Meta $meta * @property \ArrayClass $data * @property Pagination $pagination * */ class Response extends \ArrayClass < public function getMeta()< return new Meta($this->get('meta')); > public function getPagination()< return new Pagination($this->get('pagination')); > > /** * Class Meta * @package instagram * * @property integer $code */ class Meta extends \ArrayClass < >/** * Class Pagination * @package instagram * * @property integer $next_max_tag_id * @property integer $next_max_id * @property integer $next_min_id * @property string $next_url */ class Pagination extends \ArrayClass < >/** * Class TagsData * @package instagram * * @property $attribution * @property \ArrayClass $tags * @property string $type * @property $location * @property $comments * @property $filter * @property integer $created_time * @property $link * @property $likes * @property Images $images * @property \ArrayClass $users_in_photo * @property Caption $caption * @property boolean $user_has_liked * @property integer $id * @property User $user */ class TagData extends \ArrayClass < public function getImages()< return new Images($this->get('images')); > public function getCaption()< return new Caption($this->get('caption')); > public function getUser()< return new User($this->get('user')); > > /** * Class Image * @package instagram * * @property Image $low_resolution * @property Image $thumbnail * @property Image $standard_resolution */ class Images extends \ArrayClass < function __get($name) < return new Image($this->$name); > > /** * Class Image * @package instagram * * @property string $url * @property string $width * @property string $height */ class Image extends \ArrayClass < >/** * Class Caption * @package instagram * * @property integer $created_time * @property string $text * @property User $from * @property int $id * */ class Caption extends \ArrayClass< public function getFrom()< return new User($this->get('from')); > > /** * Class From * @package instagram * * @property string $username * @property string $website * @property string $profile_picture * @property integer $id * @property string $full_name * @property string $bio */ class User extends \ArrayClass
Как это выглядит в IDE:
В 2х словах. Мы получаем json от Instagram и заворачиваем его в наши классы. На выходе получаем структуру классов и помощь от нашей IDE.
Ну а теперь сам ArrayClass:
class ArrayClass implements Iterator < private $array; //. /** * @param array|ArrayClass|json_string $array */ function __construct(&$array); // . public function get($index); // . public function count(); public function ar()< return $this->array; > public function json()< return json_encode($this->array); > >
/** * Created by PhpStorm. * User: calc * Date: 02.07.14 * Time: 0:57 */ class ArrayClass implements Iterator < private $array; private $haveNext = false; /** * @param array|ArrayClass $array */ function __construct(&$array) < if($array === null) $array = array(); if($array instanceof ArrayClass)< $this->array = &$array->array; > else if(is_string($array))< $this->array = json_decode($array, true); > else< $this->array = &$array; > $this->rewind(); > function __get($name) < return $this->get($name); > function __set($name, $value) < $this->array[$name] = $value; > function __isset($name) < return isset($this->array[$name]); > function __unset($name) < unset($this->array[$name]); > public function get($index)< if(isset($this->array[$index]))< if(is_array($this->array[$index]))< return new ArrayClass($this->array[$index]); > return $this->array[$index]; > return null; //return isset($this->array[$index]) ? $this->array[$index] : null; > public function count()< return count($this->array); > public function ar()< return $this->array; > /** * (PHP 5 >= 5.0.0)
* Return the current element * @link http://php.net/manual/en/iterator.current.php * @return mixed Can return any type. */ public function current() < return current($this->array); > /** * (PHP 5 >= 5.0.0)
* Move forward to next element * @link http://php.net/manual/en/iterator.next.php * @return void Any returned value is ignored. */ public function next() < $this->haveNext = next($this->array); > /** * (PHP 5 >= 5.0.0)
* Return the key of the current element * @link http://php.net/manual/en/iterator.key.php * @return mixed scalar on success, or null on failure. */ public function key() < return key($this->array); > /** * (PHP 5 >= 5.0.0)
* Checks if current position is valid * @link http://php.net/manual/en/iterator.valid.php * @return boolean The return value will be casted to boolean and then evaluated. * Returns true on success or false on failure. */ public function valid() < return $this->haveNext; > /** * (PHP 5 >= 5.0.0)
* Rewind the Iterator to the first element * @link http://php.net/manual/en/iterator.rewind.php * @return void Any returned value is ignored. */ public function rewind() < $this->haveNext = $this->array === array() ? false : true; reset($this->array); > public function json()< return json_encode($this->array); > >
- Универсальный конструктор. Можно создать объект из массива (даже из $_POST, $_GET и т.д), из себе подобного ArrayObject, из json строки
- метод get для получения значений по ключу, удобно для цифровых значений (0..n), можно использовать в цикле for($i) $a->get($i), для массивов, которые содержат и текстовые ключи.
- Ну json() — просто завернуть в json
Вот что получаем на выходе:
Как вариант можно добавить проверки в дочерние классы.
Плюсы в том, что если вы через год залезете в свой или чужой код IDE вам даст подсказку и вам не придется перечитывать половину кода проекта, чтобы понять что за магические константы в $_GET[‘magic’] и подобных строчках кода.
Если у кого нибудь есть дополнения по использованию памяти и производительности прошу отписаться в комментариях. Спасибо.
class Get extends ArrayClass < function __construct() < parent::__construct($_GET); >> class Post extends ArrayClass < function __construct() < parent::__construct($_POST); >> class Session extends ArrayClass < function __construct($arrayName = 'session') < if(!isset($_SESSION[$arrayName])) $_SESSION[$arrayName] = array(); parent::__construct($_SESSION[$arrayName]); >public static function init() < session_start(); >>