QeePHP中的优秀函数(三)

这几个函数还是来自于QeePHP的核心类Q中。不过,我是自认为,我的configure类有部分写的比他好,不过我没有考虑删除之类的。呵呵。

    /**
     * 获取指定的设置内容
     *
     * $option 参数指定要获取的设置名。
     * 如果设置中找不到指定的选项,则返回由 $default 参数指定的值。
     *
     * @code php
     * $option_value = Q::ini('my_option');
     * @endcode
     *
     * 对于层次化的设置信息,可以通过在 $option 中使用“/”符号来指定。
     *
     * 例如有一个名为 option_group 的设置项,其中包含三个子项目。
     * 现在要查询其中的 my_option 设置项的内容。
     *
     * @code php
     * // +--- option_group
     * //   +-- my_option  = this is my_option
     * //   +-- my_option2 = this is my_option2
     * //   \-- my_option3 = this is my_option3
     *
     * // 查询 option_group 设置组里面的 my_option 项
     * // 将会显示 this is my_option
     * echo Q::ini('option_group/my_option');
     * @endcode
     *
     * 要读取更深层次的设置项,可以使用更多的“/”符号,但太多层次会导致读取速度变慢。
     *
     * 如果要获得所有设置项的内容,将 $option 参数指定为 '/' 即可:
     *
     * @code php
     * // 获取所有设置项的内容
     * $all = Q::ini('/');
     * @endcode
     *
     * @param string $option 要获取设置项的名称
     * @param mixed $default 当设置不存在时要返回的设置默认值
     *
     * @return mixed 返回设置项的值
     */
    static function ini($option, $default = null)
    {
        if ($option == '/') return self::$_ini;

        if (strpos($option, '/') === false)
        {
            return array_key_exists($option, self::$_ini)
                ? self::$_ini[$option]
                : $default;
        }

        $parts = explode('/', $option);
        $pos =& self::$_ini;
        foreach ($parts as $part)
        {
            if (!isset($pos[$part])) return $default;
            $pos =& $pos[$part];
        }
        return $pos;
    }

    /**
     * 修改指定设置的内容
     *
     * 当 $option 参数是字符串时,$option 指定了要修改的设置项。
     * $data 则是要为该设置项指定的新数据。
     *
     * @code php
     * // 修改一个设置项
     * Q::changeIni('option_group/my_option2', 'new value');
     * @endcode
     *
     * 如果 $option 是一个数组,则假定要修改多个设置项。
     * 那么 $option 则是一个由设置项名称和设置值组成的名值对,或者是一个嵌套数组。
     *
     * @code php
     * // 假设已有的设置为
     * // +--- option_1 = old value
     * // +--- option_group
     * //   +-- option1 = old value
     * //   +-- option2 = old value
     * //   \-- option3 = old value
     *
     * // 修改多个设置项
     * $arr = array(
     *      'option_1' => 'value 1',
     *      'option_2' => 'value 2',
     *      'option_group/option2' => 'new value',
     * );
     * Q::changeIni($arr);
     *
     * // 修改后
     * // +--- option_1 = value 1
     * // +--- option_2 = value 2
     * // +--- option_group
     * //   +-- option1 = old value
     * //   +-- option2 = new value
     * //   \-- option3 = old value
     * @endcode
     *
     * 上述代码展示了 Q::changeIni() 的一个重要特性:保持已有设置的层次结构。
     *
     * 因此如果要完全替换某个设置项和其子项目,应该使用 Q::replaceIni() 方法。
     *
     * @param string|array $option 要修改的设置项名称,或包含多个设置项目的数组
     * @param mixed $data 指定设置项的新值
     */
    static function changeIni($option, $data = null)
    {
        if (is_array($option))
        {
            foreach ($option as $key => $value)
            {
                self::changeIni($key, $value);
            }
            return;
        }

        if (!is_array($data))
        {
            if (strpos($option, '/') === false)
            {
                self::$_ini[$option] = $data;
                return;
            }

            $parts = explode('/', $option);
            $max = count($parts) - 1;
            $pos =& self::$_ini;
            for ($i = 0; $i < = $max; $i ++)
            {
                $part = $parts[$i];
                if ($i < $max)
                {
                    if (!isset($pos[$part]))
                    {
                        $pos[$part] = array();
                    }
                    $pos =& $pos[$part];
                }
                else
                {
                    $pos[$part] = $data;
                }
            }
        }
        else
        {
            foreach ($data as $key => $value)
            {
                self::changeIni($option . '/' . $key, $value);
            }
        }
    }

    /**
     * 替换已有的设置值
     *
     * Q::replaceIni() 表面上看和 Q::changeIni() 类似。
     * 但是 Q::replaceIni() 不会保持已有设置的层次结构,
     * 而是直接替换到指定的设置项及其子项目。
     *
     * @code php
     * // 假设已有的设置为
     * // +--- option_1 = old value
     * // +--- option_group
     * //   +-- option1 = old value
     * //   +-- option2 = old value
     * //   \-- option3 = old value
     *
     * // 替换多个设置项
     * $arr = array(
     *      'option_1' => 'value 1',
     *      'option_2' => 'value 2',
     *      'option_group/option2' => 'new value',
     * );
     * Q::replaceIni($arr);
     *
     * // 修改后
     * // +--- option_1 = value 1
     * // +--- option_2 = value 2
     * // +--- option_group
     * //   +-- option2 = new value
     * @endcode
     *
     * 从上述代码的执行结果可以看出 Q::replaceIni() 和 Q::changeIni() 的重要区别。
     *
     * 不过由于 Q::replaceIni() 速度比 Q::changeIni() 快很多,
     * 因此应该尽量使用 Q::replaceIni() 来代替 Q::changeIni()。
     *
     * @param string|array $option 要修改的设置项名称,或包含多个设置项目的数组
     * @param mixed $data 指定设置项的新值
     */
    static function replaceIni($option, $data = null)
    {
        if (is_array($option))
        {
            self::$_ini = array_merge(self::$_ini, $option);
        }
        else
        {
            self::$_ini[$option] = $data;
        }
    }

    /**
     * 删除指定的设置
     *
     * Q::cleanIni() 可以删除指定的设置项目及其子项目。
     *
     * @param mixed $option 要删除的设置项名称
     */
    static function cleanIni($option)
    {
        if (strpos($option, '/') === false)
        {
            unset(self::$_ini[$option]);
        }
        else
        {
            $parts = explode('/', $option);
            $max = count($parts) - 1;
            $pos =& self::$_ini;
            for ($i = 0; $i < = $max; $i ++)
            {
                $part = $parts[$i];
                if ($i < $max)
                {
                    if (!isset($pos[$part]))
                    {
                        $pos[$part] = array();
                    }
                    $pos =& $pos[$part];
                }
                else
                {
                    unset($pos[$part]);
                }
            }
        }
    }

QeePHP中的优秀函数(二)

这两个函数来自于Helper_Array,我觉得是非常常用的方法,功能也比较强大。适合大家使用。

    /**
     * 将一个平面的二维数组按照指定的字段转换为树状结构
     *
     * 用法:
     * @code php
     * $rows = array(
     *     array('id' => 1, 'value' => '1-1', 'parent' => 0),
     *     array('id' => 2, 'value' => '2-1', 'parent' => 0),
     *     array('id' => 3, 'value' => '3-1', 'parent' => 0),
     *
     *     array('id' => 7, 'value' => '2-1-1', 'parent' => 2),
     *     array('id' => 8, 'value' => '2-1-2', 'parent' => 2),
     *     array('id' => 9, 'value' => '3-1-1', 'parent' => 3),
     *     array('id' => 10, 'value' => '3-1-1-1', 'parent' => 9),
     * );
     *
     * $tree = Helper_Array::tree($rows, 'id', 'parent', 'nodes');
     *
     * dump($tree);
     *   // 输出结果为:
     *   // array(
     *   //   array('id' => 1, ..., 'nodes' => array()),
     *   //   array('id' => 2, ..., 'nodes' => array(
     *   //        array(..., 'parent' => 2, 'nodes' => array()),
     *   //        array(..., 'parent' => 2, 'nodes' => array()),
     *   //   ),
     *   //   array('id' => 3, ..., 'nodes' => array(
     *   //        array('id' => 9, ..., 'parent' => 3, 'nodes' => array(
     *   //             array(..., , 'parent' => 9, 'nodes' => array(),
     *   //        ),
     *   //   ),
     *   // )
     * @endcode
     *
     * 如果要获得任意节点为根的子树,可以使用 $refs 参数:
     * @code php
     * $refs = null;
     * $tree = Helper_Array::tree($rows, 'id', 'parent', 'nodes', $refs);
     *
     * // 输出 id 为 3 的节点及其所有子节点
     * $id = 3;
     * dump($refs[$id]);
     * @endcode
     *
     * @param array $arr 数据源
     * @param string $key_node_id 节点ID字段名
     * @param string $key_parent_id 节点父ID字段名
     * @param string $key_childrens 保存子节点的字段名
     * @param boolean $refs 是否在返回结果中包含节点引用
     *
     * return array 树形结构的数组
     */
    static function toTree($arr, $key_node_id, $key_parent_id = 'parent_id',
                           $key_childrens = 'childrens', & $refs = null)
    {
        $refs = array();
        foreach ($arr as $offset => $row)
        {
            $arr[$offset][$key_childrens] = array();
            $refs[$row[$key_node_id]] =& $arr[$offset];
        }

        $tree = array();
        foreach ($arr as $offset => $row)
        {
            $parent_id = $row[$key_parent_id];
            if ($parent_id)
            {
                if (!isset($refs[$parent_id]))
                {
                    $tree[] =& $arr[$offset];
                    continue;
                }
                $parent =& $refs[$parent_id];
                $parent[$key_childrens][] =& $arr[$offset];
            }
            else
            {
                $tree[] =& $arr[$offset];
            }
        }

        return $tree;
    }

    /**
     * 将树形数组展开为平面的数组
     *
     * 这个方法是 tree() 方法的逆向操作。
     *
     * @param array $tree 树形数组
     * @param string $key_childrens 包含子节点的键名
     *
     * @return array 展开后的数组
     */
    static function treeToArray($tree, $key_childrens = 'childrens')
    {
        $ret = array();
        if (isset($tree[$key_childrens]) && is_array($tree[$key_childrens]))
        {
            $childrens = $tree[$key_childrens];
            unset($tree[$key_childrens]);
            $ret[] = $tree;
            foreach ($childrens as $node)
            {
                $ret = array_merge($ret, self::treeToArray($node, $key_childrens));
            }
        }
        else
        {
            unset($tree[$key_childrens]);
            $ret[] = $tree;
        }
        return $ret;
    }

不过显而易见,这两个函数,都不需要多介绍,tree2list,list2tree,想想也知道怎么用,再加上注释又比较全。
可惜QeePHP不再开发,而ThinkPHP积下来的问题又很多,改动起来也非常痛苦。所以我开始慢慢分析一下。

QeePHP中的优秀函数(一)

基类Q中的normalize。

    /**
     * 对字符串或数组进行格式化,返回格式化后的数组
     *
     * $input 参数如果是字符串,则首先以“,”为分隔符,将字符串转换为一个数组。
     * 接下来对数组中每一个项目使用 trim() 方法去掉首尾的空白字符。最后过滤掉空字符串项目。
     *
     * 该方法的主要用途是将诸如:“item1, item2, item3” 这样的字符串转换为数组。
     *
     * @code php
     * $input = 'item1, item2, item3';
     * $output = Q::normalize($input);
     * // $output 现在是一个数组,结果如下:
     * // $output = array(
     * //   'item1',
     * //   'item2',
     * //   'item3',
     * // );
     *
     * $input = 'item1|item2|item3';
     * // 指定使用什么字符作为分割符
     * $output = Q::normalize($input, '|');
     * @endcode
     *
     * @param array|string $input 要格式化的字符串或数组
     * @param string $delimiter 按照什么字符进行分割
     *
     * @return array 格式化结果
     */
    static function normalize($input, $delimiter = ',')
    {
        if (!is_array($input))
        {
            $input = explode($delimiter, $input);
        }
        $input = array_map('trim', $input);
        return array_filter($input, 'strlen');
    }

看到这个方法,其实应该感觉得到它的用户,确实,大多数情况下,我们都是用explode来分割字符串的,但事实上,你不能保证别人给你的字符串有没有多余的空格,或者无效的字符串,因此,通过这个函数,就可以去除掉很无效的值 。建议使用它来代替explode,但,如果确实是很规则的,还是用explode吧,毕竟,如果这个分割出来的数组很大,效率肯定比explode低很多了。