PHP:修改在运行时未知结构数组;什么是最优雅的解决方案? [英] PHP: Modifying array with unknown structure at runtime; what is the most elegant solution?

查看:155
本文介绍了PHP:修改在运行时未知结构数组;什么是最优雅的解决方案?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题

我有一个函数,在嵌套阵列,其中阵列的结构和嵌套的未知的在运行时。是已知的所有是一些目标字段名和一些叶子的所需的值。

问题

1),我希望能修改这个未知的结构,仍然有code可读和老乡程序员容易理解。什么(如果有的话)解决方案将允许我做这样的事情在PHP?

  //伪code的东西,我想能够做到
//这是还挺像一回事XPATH,但对于原生PHP数组// *找到与布拉德每值FNAME *,并更改为布莱恩
$ mydata-> find_all('*:FNAME') - GT; where_value_eq('布拉德') - GT; set_equal_to('布赖恩');//找到*第一个* fave_color并将其设置为绿色
$ mydata->找到('*:fave_color') - GT;得到(0) - > set_equal_to(绿色);

2)如果有什么在那里,让我做到这一点,是有什么,什么,至少接近什么,我希望能在这里完成的精神?

样本数组

  $ MYDATA =阵列(
   人=>阵列(
      阵列('FNAME'=>爱丽丝),
      阵列('FNAME'=>'布拉德'),
      阵列('FNAME'=>'克里斯'),
    )
   '动物'=>阵列(
      阵列('FNAME'=>'恐龙'),
      阵列('FNAME'=>灵犬莱西),
      阵列('FNAME'=>'布拉德'),
    )
    设置=>阵列(
      用户_ preFS'=>阵列(
        'localhost'的= GT;阵列(
          fave_color'=>蓝色,
        )
      )
    )
    '地方'=>阵列(
      阵列('状态'=>'纽约',
            '城市'=>阵列(
              '名'=>阿尔巴尼,
              '名'=>'水牛',
              '名'=>'康宁',
            )
            国家= GT;'加州,
            '城市'=>阵列(
              '名'=>阿纳海姆,
              '名'=>'贝克斯菲尔德',
              '名'=>'卡尔斯巴德',
            )
      )
    )
);


解决方案

虽然我认为你应该有明确的操作坚持在我的previous答案,无聊和阴谋得到了我的好;)

它可能有孔(和显然缺乏文档),但如果你坚持这条路线,它应该让你开始:

 类搜索{
    保护$的数据;    公共职能__construct(安培; $数据){
        如果(!is_array($数据)){
            抛出新InvalidArgumentException;
        }        $这个 - >数据=安培; $的数据;
    }    公共职能全部(){
        返回$这个 - >找到();
    }    公共职能的发现($ EX pression = NULL){
        如果(!使用isset($ EX pression)){
            返回新结果($这个 - >数据);
        }        $结果=阵列();
        $这个 - > _find(爆炸(':',$ EX pression),$这个 - >的数据,$结果);
        返回新结果($结果);
    }    保护功能_find($零部件,&安培; $的数据,和放大器; $结果){
        如果(!$件){
            返回;
        }        $ currentParts = $部分;
        $搜索= array_shift($ currentParts);
        如果($通配符= $搜索=='*'){
            $搜索= array_shift($ currentParts);
        }        的foreach($数据,$关键=>&安培; $值){
            如果($关键=== $搜索){
                如果($ currentParts){
                    $这个 - > _find($ currentParts,价值$,$结果);
                }其他{
                    $结果[] =&安培; $价值;
                }
            }否则如果($通配符和放大器;&安培; is_array($值)){
                $这个 - > _find($件,价值$,$结果);
            }
        }
    }
}类结果{
    保护$的数据;    公共职能__construct(安培; $数据){
        $这个 - >数据= $的数据;
    }    公共职能的get($指数,$限制= 1){
        $这个 - >数据= array_slice($这个 - >的数据,$指数,$限制);
        返回$这一点;
    }    公共职能set_equal_to($值){
        的foreach($这个 - >数据&安培; $基准面){
            $基准= $价值;
        }
    }    公共职能__call($方法的$ args){
        (!preg_match('/ ^ _哪里(密钥?|值)_(EQ?|含)$ / I',$方法,$ M)){如果
            抛出新BadFunctionCallException;
        }        如果(!使用isset(的$ args [0])){
            抛出新InvalidArgumentException;
        }        $操作=的$ args [0];
        $ isKey =用strtolower($ M [1])=='键';
        $方法=阵列('结果','_compare'(用strtolower($ M [2])=='情商''EqualTo':?'包含'));        $ RET =阵列();
        的foreach($这个 - >数据作为$关键=>&安培; $基准面){
            如果(call_user_func($方法,$ isKey $键:$数据,$操作数)){
                $沤[] =&放大器; $数据;
            }
        }        $这个 - >数据= $ RET;
        返回$这一点;
    }    保护功能_compareEqualTo(价值$,$测试){
        返回$价值== $测试;
    }    保护功能_compareContains(价值$,$测试){
        返回strpos($价值$测试)==假的!;
    }
}$取景器=新的Finder($ MYDATA);
$ finder->找到('*:FNAME') - GT; where_value_eq('布拉德') - GT; set_equal_to('布赖恩');
$ finder->找到('*:fave_color') - GT;得到(0) - > set_equal_to(绿色);
$finder->find('places:*:cities:*:name')->where_value_contains('ba')->set_equal_to('Stackoton');的print_r($ MYDATA);

PROBLEM

I have a function that takes in a nested array where the structure and nesting of the array is unknown at run-time. All that is known is some of the target fieldnames and desired values of some of the leafs.

QUESTIONS

1) I am hoping to modify this unknown structure and still have the code be readable and easily understood by fellow programmers. What (if any) solution will allow me to do things like this in PHP?

// Pseudo-code for things I would like to be able to do
// this is kinda like the same thing as XPATH, but for native PHP array

// find *every* fname with value of "Brad" and change it to "Brian"
$mydata->find_all('*:fname')->where_value_eq('Brad')->set_equal_to('Brian');

// find *the first* fave_color and set it to "Green"
$mydata->find('*:fave_color')->get(0)->set_equal_to('Green');

2) If there is nothing out there that will let me do this, is there something, anything, that at least comes close to the spirit of what I am hoping to accomplish here?

SAMPLE ARRAY

$mydata = array(
   'people' => array(
      array('fname'=>'Alice'),
      array('fname'=>'Brad'),
      array('fname'=>'Chris'),
    ),
   'animals' => array(
      array('fname'=>'Dino'),
      array('fname'=>'Lassie'),
      array('fname'=>'Brad'),
    ),
    'settings' => array(
      'user_prefs'=>array(
        'localhost'=>array(
          'fave_color'=>'blue',
        ),
      ),
    ),
    'places' => array(
      array('state'=>'New york',
            'cities'=>array(
              'name'=>'Albany',
              'name'=>'Buffalo',
              'name'=>'Corning',
            ),
            'state'=>'California',
            'cities'=>array(
              'name'=>'Anaheim',
              'name'=>'Bakersfield',
              'name'=>'Carlsbad',
            ),            
      ),
    ),
);

解决方案

Although I maintain that you should stick with explicit manipulation as in my previous answer, boredom and intrigue got the better of me ;)

It probably has holes (and clearly lacks docs) but if you insist on this route, it should get you started:

class Finder {
    protected $data;

    public function __construct(&$data) {
        if (!is_array($data)) {
            throw new InvalidArgumentException;
        }

        $this->data = &$data;
    }

    public function all() {
        return $this->find();
    }

    public function find($expression = null) {
        if (!isset($expression)) {
            return new Results($this->data);
        }

        $results = array();
        $this->_find(explode(':', $expression), $this->data, $results);
        return new Results($results);
    }

    protected function _find($parts, &$data, &$results) {
        if (!$parts) {
            return;
        }

        $currentParts = $parts;
        $search = array_shift($currentParts);
        if ($wildcard = $search == '*') {
            $search = array_shift($currentParts);
        }

        foreach ($data as $key => &$value) {
            if ($key === $search) {
                if ($currentParts) {
                    $this->_find($currentParts, $value, $results);
                } else {
                    $results[] = &$value;
                }
            } else if ($wildcard && is_array($value)) {
                $this->_find($parts, $value, $results);
            }
        }
    }
}

class Results {
    protected $data;

    public function __construct(&$data) {
        $this->data = $data;
    }

    public function get($index, $limit = 1) {
        $this->data = array_slice($this->data, $index, $limit);
        return $this;
    }

    public function set_equal_to($value) {
        foreach ($this->data as &$datum) {
            $datum = $value;
        }
    }

    public function __call($method, $args) {
        if (!preg_match('/^where_?(key|value)_?(eq|contains)$/i', $method, $m)) {
            throw new BadFunctionCallException;
        }

        if (!isset($args[0])) {
            throw new InvalidArgumentException;
        }

        $operand = $args[0];
        $isKey = strtolower($m[1]) == 'key';
        $method = array('Results', '_compare' . (strtolower($m[2]) == 'eq' ? 'EqualTo' : 'Contains'));

        $ret = array();
        foreach ($this->data as $key => &$datum) {
            if (call_user_func($method, $isKey ? $key : $datum, $operand)) {
                $ret[] = &$datum;
            }
        }

        $this->data = $ret;
        return $this;
    }

    protected function _compareEqualTo($value, $test) {
        return $value == $test;
    }

    protected function _compareContains($value, $test) {
        return strpos($value, $test) !== false;
    }
}

$finder = new Finder($mydata);
$finder->find('*:fname')->where_value_eq('Brad')->set_equal_to('Brian');
$finder->find('*:fave_color')->get(0)->set_equal_to('Green');
$finder->find('places:*:cities:*:name')->where_value_contains('ba')->set_equal_to('Stackoton');

print_r($mydata);

这篇关于PHP:修改在运行时未知结构数组;什么是最优雅的解决方案?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆