Как Simple XML использует оператор []? - PullRequest
1 голос
/ 20 марта 2009

В PHP вы можете использовать квадратные скобки для элемента для доступа к атрибутам:

$node = /* SimpleXMLElement */
$id = $node['id'];

Что странно в том, что $id это не строка, а другая SimpleXMLElement. Почему это не строка? Я использую strval() повсюду.

Как работают квадратные скобки? Могу ли я сделать это с моими собственными классами? Я ничего не видел в документации по этому поводу.

Ответы [ 4 ]

3 голосов
/ 20 марта 2009

Вы можете предоставить Array-подобный доступ к вашему объекту, реализовав ArrayAccess интерфейс , который является частью стандартной библиотеки PHP. Этот интерфейс является одним из тех, «даже если у вас не установлено полное расширение стандартной библиотеки PHP, у вас все еще есть этот интерфейс, доступный в PHP 5».

Путем реализации этого интерфейса и определения четырех методов для вашего класса

public boolean offsetExists  ( string $offset  )
public mixed offsetGet ( string $offset )
public void offsetSet ( string $offset , string $value )
public void offsetUnset ( string $offset )

вы должны иметь возможность использовать квадратные скобки с вашими объектами.

Что касается самого SimpleXML, я не уверен, реализует ли он на самом деле интерфейс ArrayAccess или что-то еще происходит за кулисами в исходном тексте PHP, что дает ему эти сверхспособности.

1 голос
/ 05 ноября 2012

Что касается самого SimpleXML, то это внутренний класс. Единственный интерфейс, который он реализует для пользовательского пространства PHP, это Traversable.

Внутренне, когда к нему обращаются в квадратных скобках, SimpleXML ищет вещи в зависимости от значения и типа индекса / ключа.

Если тип является целочисленным (длинным), он пытается найти нумерованный элемент с нулевым индексом и предложить его значение. Если у вас есть конкретный элемент узла, например $root для корневого элемента, $root[0] будет представлять значение этого элемента:

$root = new SimpleXMLElement('<root a="vala"></root>');
$root[0] = 'hello'; 
# <root a="vala">hello</root>
#                ^^^^^- changed value                     

Корневой элемент немного неинтересен, потому что существует только один. Это более интересно с элементами, у которых есть родители.

$root = new SimpleXMLElement('<root a="vala"><child /></root>');
$root->child[0] = 'hello'; 
# <root a="vala"><child>hello</child></root>
#                       ^^^^^- changed value

Устанавливает значение узла первого child элемента. Индекс up-one добавит нового потомка:

$root = new SimpleXMLElement('<root a="vala"><child /></root>');
$root->child[1] = 'hello'; 
# <root a="vala"><child/><child>hello</child></root>
#                        ^--  added child --^

Это в значительной степени работает как с массивами. Строки, которые являются целым числом, работают как целое число:

$root->child['1'] = 'hello'; 
# <root a="vala"><child/><child>hello</child></root>
#                        ^--  added child --^

И, оставив скобки пустыми, в конце добавим новый элемент:

$root->child[] = 'hello';
$root->child[] = 'world';
# <root a="vala"><child/><child>hello</child><child>world</child></root>

Пока что для целых чисел и смещения "нет". Как и в случае стандартного массива PHP, его не следует путать с передачей NULL. Это будет преобразовано в пустую строку "".

Для любой строки SimpleXML будет искать узел атрибута вместо узла дочернего элемента:

$root = new SimpleXMLElement('<root a="vala"></root>');
echo $root['a'], "\n"; # vala

Это также работает для добавления атрибутов:

$root = new SimpleXMLElement('<root a="vala"></root>');
$root['b'] = 'hello'; # <root a="vala" b="hello"/>

В граничном регистре используется пустая строка ("") или NULL, поскольку simplexml выдает ошибку, говоря, что атрибут без имени недопустим. Имеет смысл, так как атрибуты должны иметь имя:

Предупреждение: main (): невозможно записать или создать безымянный атрибут в ...

Еще один особый случай - поддержка магического метода __toString . Если вы передадите объект как смещение, SimpleXML попытается преобразовать его в строку с помощью магического метода. Затем он будет использовать возвращенную строку, как описано выше.


Подводя итог: Класс SimpleXMLElement не реализует интерфейс ArrayAccess, но, поскольку это внутренний класс, он может добавить поведение, подобное массиву. И SimpleXML делает именно это.

Функция полезности в источниках PHP называется sxe_prop_dim_read.


А что, если вы хотите сделать что-то похожее с вашими классами?

Для этого и нужен интерфейс ArrayAccess. Реализуйте это в ваших собственных классах. PHP уже берет на себя часть внутренней работы, чтобы сделать смещения более массивными: integer stay integer; Строка, такая как целое число, преобразуется в целое число, а логические значения преобразуются в целое число.

Однако ArrayAccess допускает больше, чем стандартный массив: допустимыми смещениями являются числа с плавающей запятой, NULL, массивы и объекты.

Особенно с NULL, вы не можете отличаться между установкой смещения NULL или установкой нового элемента - оба случая предоставят NULL как смещение.

Пример реализации интерфейса доступен с другим вопросом: PHP, SPL, интерфейс ArrayAccess .

1 голос
/ 21 марта 2009

Полагаю, вы можете расширить класс SimpleXML и реализовать в нем ArrayAccess.

0 голосов
/ 20 марта 2009

Полагаю, это волшебный метод __ get ()

Редактировать: Я думаю, что я угадал. Еще не знал об интерфейсе доступа к массиву.

...