28 September 2012

最近在开发中由于需要对一个数组进行三层循环处理,介于使用PHP中的foreach或for循环要比PHP本身array处理函数的效率增加40%-100%(此处后面提交文章来解释为什么会增加这么多的效率开销,或者读者可以搜索下,很多人进行了相关测试),所以采用了array_walk方法来满足自己需求上的使用,下面介绍下我的使用过程:

本人有一个待处理数组,结构如下:

<?php
    $aNeedToDo = array(
        1 => array(
            array(
                'model' => object,
                'node' => object,
            ),
            ...
        ),
        4 => array(
            array(
                'model' => object,
                'node' => object,
            ),
            ...
        ),
        32 => array(
            array(
                'model' => object,
                'node' => object,
            ),
            ...
        ),
    );

现在笔者要对其进行处理,最终目的是根据最底下的一维数据对node进行定型且需要对于$aNeedToDo中key值大于1的数组生成一个关联父节点数据,实现关联,并需要将处理结果保存起来最终反馈给用户,于是本人定义了一个回调,用于处理这个数组。

<?php
    function _handleTodoList($aTodoListItem, $nNodeCount, &$aReturnData) {
        if($nNodeCount == 1) {//不需要生成父节点
            array_walk($aTodoListItem, '_handleNotParentNode', $aReturnData);
        } else {//需要生成父节点
            $aParentTodoList = array_chunk($aTodoListItem, $aNodeCount);//按照父节点中需要关联的子节点个数对子节点集合进行分组
            array_walk($aParentTodoList'_handleParentNode', $aReturnData);
        }
    }

    function _handleNotParentNode($aNodeItem, $key, &$aReturnData) {
        //do something
        $aReturnData[] = array('status' => 0/1, 'msg' => 'xxx');
    }

    function _handleParentNode($aParentNodeItem, $key, &$aReturnData) {
        //do other something
        $aReturnData[] = array('status' => 0/1, 'msg' => 'xxx');
    }

实现好以上方法,开始对$aNeedToDo进行处理

<?php
    $aReturnData = array();
    array_walk($aNeedToDo, '_handleTodoList', $aReturnData);

按照以往对数组引用的理解此处在array_walk处理后$aReturnData会存在回调函数中保存的处理信息,恰恰相反的时候在array_walk处理过后没有任何结果,于是在array_walk的回调函数内部加上var_dump打印$aReturnData,发现,其实每次调用回调的时候确实$aReturnData是有变化的,那么说明函数声明引用处理是没有问题的,查了一遍PHP手册一直都无解为什么会这样,后来和同事一起研究了下,推断是array_walk在本身接受参数的方式不是引用导致,后来重新找了一份带有评论的PHP手册,大家原来都有对此疑惑的时候,所以想要以引用方式去操作回调的是后上面的代码就要修改一下了。

<?php
    function _handleTodoList($aTodoListItem, $nNodeCount, &$aReturnData) {
        if($nNodeCount == 1) {//不需要生成父节点
            array_walk($aTodoListItem, '_handleNotParentNode', &$aReturnData);
        } else {//需要生成父节点
            $aParentTodoList = array_chunk($aTodoListItem, $aNodeCount);//按照父节点中需要关联的子节点个数对子节点集合进行分组
            array_walk($aParentTodoList'_handleParentNode', &$aReturnData);
        }
    }

    function _handleNotParentNode($aNodeItem, $key, &$aReturnData) {
        //do something
        $aReturnData[] = array('status' => 0/1, 'msg' => 'xxx');
    }

    function _handleParentNode($aParentNodeItem, $key, &$aReturnData) {
        //do other something
        $aReturnData[] = array('status' => 0/1, 'msg' => 'xxx');
    }

    $aReturnData = array();
    array_walk($aNeedToDo, '_handleTodoList', &$aReturnData);

歧义问题迎刃而解!不过这种使用方式和PHP建议的只在方法声明时声明为引用,调用不需要声明违背,还不是很了解为什么这个函数要这样设计,后期可以针对PHP源码加以分析。

  • 分享到: