PHP 7 - итеративно заполнять многоуровневый массив в обратном вызове - PullRequest
0 голосов
/ 28 сентября 2018

Мне нужно создать сложный многоуровневый массив только в обратном вызове, одно атомарное обновление за вызов.

Причина этого: обратный вызов много раз вызывается из итеративного парсера.Наконец, он должен создать десериализованный PHP-массив анализируемого двоичного формата.

Вот исполняемый код:

const ACTION_VALUE = 1;
const ACTION_ENTER = 2;
const ACTION_LEAVE = 3;

function callback($action, $value, &$param)
{
   switch ($action) 
   {
    case ACTION_ENTER:
        $param['parent'][] = &$param['current'];
        $param['current'][] = [];

        end($param['current']);                
        $param['current'] = &$param['current'][key($param['current'])];
    break;

    case ACTION_LEAVE:
        unset($param['current']);
        $param['current'] = array_pop($param['parent']);
        end($param['current']);
    break;

    case ACTION_VALUE:
        $param['current'][] = $value;
    break;
   }
}

// prepare container
$arr = [];
$arr['data'] = [];
$arr['current'] = &$arr['data'];
$arr['parent'] = [];

// callback invocations
callback(ACTION_VALUE, 1, $arr);
callback(ACTION_VALUE, 2, $arr);
callback(ACTION_ENTER, 0, $arr);
callback(ACTION_VALUE, 10, $arr);
callback(ACTION_VALUE, 11, $arr);
callback(ACTION_LEAVE, 0, $arr);
callback(ACTION_VALUE, 3, $arr);
callback(ACTION_VALUE, 4, $arr);

// now see result
var_dump(json_encode($arr['data']));

Попробуйте здесь

Вышепример печатает:

[1,2,[10,11]], но должен [1,2,[10,11],3,4].

Обновление: Многоуровневый означает произвольные массивы произвольной глубины.

Обновление: Проблема была с array_pop(), см. Ниже принятый ответ для фиксированной версии.

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

Я думаю, что проблема в array_pop, которая не возвращает фактическую ссылку на последний элемент.Это работает:

<?php

const ACTION_VALUE = 1;
const ACTION_ENTER = 2;
const ACTION_LEAVE = 3;

function callback($action, $value, &$param)
{
    switch ($action) {
        case ACTION_ENTER:
            $param['parent'][] = &$param['current'];
            $param['current'][] = [];

            end($param['current']);
            $param['current'] = &$param['current'][key($param['current'])];
            break;

        case ACTION_LEAVE:
            unset($param['current']);
            end($param['parent']);
            $param['current'] = &$param['parent'][key($param['parent'])];
            unset($param['parent'][key($param['parent'])]);
            end($param['current']);
            break;

        case ACTION_VALUE:
            $param['current'][] = $value;
            break;
    }
}

// prepare container
$arr = [];
$arr['data'] = [];
$arr['current'] = &$arr['data'];
$arr['parent'] = [];

// callback invocations
callback(ACTION_VALUE, 1, $arr);
callback(ACTION_VALUE, 2, $arr);
callback(ACTION_ENTER, 0, $arr);
callback(ACTION_VALUE, 10, $arr);
callback(ACTION_VALUE, 11, $arr);
callback(ACTION_ENTER, 0, $arr);
callback(ACTION_VALUE, 40, $arr);
callback(ACTION_VALUE, 41, $arr);
callback(ACTION_LEAVE, 0, $arr);
callback(ACTION_LEAVE, 0, $arr);
callback(ACTION_VALUE, 3, $arr);
callback(ACTION_VALUE, 4, $arr);

// now see result
var_dump(json_encode($arr['data']));
0 голосов
/ 28 сентября 2018

Вы можете сделать что-то подобное, это определенно упрощает то, что вы пытаетесь сделать.У него просто разные значения базового массива, но он достаточно похож, поэтому я думаю, что он должен работать для вашего приложения.

Изменения: Реструктуризация массива и использование строки addTo в качестве «указателя»

const ACTION_VALUE = 1;
const ACTION_ENTER = 2;
const ACTION_LEAVE = 3;

// prepare container
$arr = [];
$arr['data'] = [];
$arr['addTo'] = 'data';
$arr['temp'] = [];

function callback($action, $value, &$param)
{
    switch ($action)
    {
        case ACTION_ENTER:
            $param['addTo'] = 'temp';
            break;

        case ACTION_LEAVE:
            $param['addTo'] = 'data';
            $param['data'][] = $param['temp'];
            $param['temp'] = [];
            break;

        case ACTION_VALUE:
            $param[$param['addTo']][] = $value;
            break;
    }
}



// callback invocations
callback(ACTION_VALUE, 1, $arr);
callback(ACTION_VALUE, 2, $arr);
callback(ACTION_ENTER, 0, $arr);
callback(ACTION_VALUE, 10, $arr);
callback(ACTION_VALUE, 11, $arr);
callback(ACTION_LEAVE, 0, $arr);
callback(ACTION_VALUE, 3, $arr);
callback(ACTION_VALUE, 4, $arr);

// now see result
var_dump(json_encode($arr['data']));
...