Доступ к вложенному свойству в объекте stdClass со строковым представлением узла - PullRequest
0 голосов
/ 21 апреля 2019

Учитывая переменную, которая содержит эту строку:

$property = 'parent->requestdata->inputs->firstname';

И объект:

$obj->parent->requestdata->inputs->firstname = 'Travis';

Как мне получить доступ к значению 'Travis', используя строку?Я попытался это:

$obj->{$property}

Но он ищет свойство с именем 'parent-> requestdata-> input-> firstname', а не свойство, расположенное в $ obj-> parent-> requestdtaa-> input->firstname`

Я пробовал различные типы конкатенации, использование var_export () и другие.Я могу разбить его на массив, а затем зациклить массив, как в этот вопрос .

Но переменная $ property может содержать значение, которое углубляется на 16 уровней.И данные, которые я анализирую, могут иметь сотни свойств, которые мне нужно импортировать, поэтому циклический просмотр и возврат значений на каждой итерации, пока я не достигну элементов уровня 16 X 100, кажется действительно неэффективным;особенно с учетом того, что я знаю фактическое местоположение объекта в начале.

Как получить значение 'Travis' с учетом (stdClass)$obj и (string)$property?

Ответы [ 2 ]

0 голосов
/ 22 апреля 2019

Мои начальные поиски не дали много результатов, однако, после обдумывания более широкого круга поисковых терминов, я нашел другие вопросы по SO, которые касались подобных проблем. Я придумал три решения. Все будет работать, но не все будут работать для всех.

Решение 1 - Цикл

Будет работать подход, аналогичный вопросу, на который ссылается мой исходный вопрос, или цикл, предложенный @ miken32.

Решение 2 - анонимная функция

Строка может быть взорвана в массив. Затем массив может быть проанализирован с помощью array_reduce () для получения результата. В моем случае рабочий код (с проверкой неправильных / несуществующих имен / написаний свойств) был таким (PHP 7+):

//create object - this comes from and external API in my case, but I'll include it here 
//so that others can copy and paste for testing purposes

$obj = (object)[
    'parent' => (object)[
        'requestdata' => (object)[
            'inputs' => (object)[
                'firstname' => 'Travis'
             ]
         ]
    ]
];

//string representing the property we want to get on the object

$property = 'parent->requestdata->inputs->firstname';

$name = array_reduce(explode('->', $property), function ($previous, $current) {
    return is_numeric($current) ? ($previous[$current] ?? null) : ($previous->$current ?? null); }, $obj);

var_dump($name); //outputs Travis

см. этот вопрос для получения потенциально важной информации и кода, на котором я основал свой ответ.

Решение 3 - компонент доступа к свойствам Symfony

В моем случае было легко использовать composer, чтобы требовать этот компонент. Это позволяет получить доступ к свойствам массивов и объектов, используя простые строки. Вы можете прочитать о том, как его использовать на сайте Symfony. Основным преимуществом для меня по сравнению с другими вариантами была включенная проверка ошибок.

Мой код в итоге выглядел так:

//create object - this comes from and external API in my case, but I'll include it here 
//so that others can copy and paste for testing purposes
//don't forget to include the component at the top of your class
//'use Symfony\Component\PropertyAccess\PropertyAccess;'

$obj = (object)[
    'parent' => (object)[
        'requestdata' => (object)[
            'inputs' => (object)[
                'firstname' => 'Travis'
             ]
         ]
    ]
];

//string representing the property we want to get on the object
//NOTE: syfony uses dot notation. I could not get standard '->' object notation to work.

$property = 'parent.requestdata.inputs.firstname';

//create symfony property access factory

$propertyAccessor = PropertyAccess::createPropertyAccessor();

//get the desired value

$name = $propertyAccessor->getValue($obj, $property);

var_dump($name); //outputs 'Travis'

Все три варианта будут работать. Выберите тот, который работает для вас.

0 голосов
/ 21 апреля 2019

Вы правы, что вам придется выполнять итерацию цикла для каждого вложенного объекта, но вам не нужно циклически просматривать «сотни свойств» для каждого из них, вы просто получаете доступ к тому, который ищетеfor:

$obj = new SomeObject;
$property = 'parent->requestdata->inputs->firstname';
$props = explode("->", $property);
while ($props) {
    $prop = array_shift($props);
    $obj = $obj->$prop ?? null;
}

Полностью не проверено, но похоже, что оно должно работать и быть достаточно производительным.Тем не менее, это звучит так, как будто это может быть проблема XY .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...