P

PHP 实现 数组转换成可以遍历的对象,既可以使用数组方式访问,又可以按照之前的数组形式访问

xyj2156 PHP 2018-04-22

数组转换

这里只说明如果将一个数组转换问对象后,既可以按照数组方式访问和遍历,又可以使用对象的属性方式访问的。

先弄一个可以遍历的类再说

这里借助的是 迭代器接口 Iterator

官网对应链接:http://php.net/manual/zh/language.generators.comparison.php

1. 先写一个抽象类 实现 迭代器 接口
2. 实现迭代器接口所有的方法。

使用静态延迟绑定实现 递归生成,而不是只有一级的可以实现;

这样我们就得到一个可以遍历的对象了。

看一个例子:

abstract class CommonIterator implements  \Iterator
 {
        protected $array;

        /**
         * 构造函数
         * @param Array $arr 要转换的数组
         */
        public function __construct(Array $arr)
        {
            $this -> array = $arr;
            foreach ($arr as $k => $v) {
                if(is_array($v)){
                    $this -> array [$k] = new static($v);
                    continue;
                }
                $this -> array [$k] = ($v);
            }
        }

        /**
         * 初始化数组时 调用的方法
         * @return [type] [description]
         */
        public function rewind()
        {
            return reset($this -> array);
        }

        /**
         * 检测 数组中键存不存在
         * @return [type] [description]
         */
        public function valid()
        {
            return array_key_exists($this -> key(), $this -> array);
        }

        /**
         * 获取当前数组指针指向的内容
         * @return mixed 指向的内容
         */
        public function current()
        {
            return current($this -> array);
        }

        /**
         * 获取指针指向的键
         * @return int|string 指针指向的键
         */
        public function key()
        {
            return key($this -> array);
        }

        /**
         * 使指针指向下一位
         * @return function [description]
         */
        public function next()
        {
            return next($this -> array);
        }
}

访问对象的属性就是访问 数组中的键值的实现

其实很简单,通过魔术方法 __get ,就可以实现。

在前面的基础上 添加魔术方法。

1. 再写一个抽象类继承上面的抽象类
2. 添加魔术方法
3. 既然获取有了判断是否设置也写上吧,万一用上了呢。

下面代码:

abstract class BaseCommon extends CommonIterator
{
        /**
         * 对象魔术方法 当属性没有的时候或者属性私有的时候 触发这个方法
         * @param  string $name 属性名
         * @return mixed        返回的属性对应的值
         */
        public function __get($name)
        {
            if(isset($this -> array[$name]))
                return $this -> array[$name];
            return null;
        }
        /**
         * 判断对象属性存不存在
         * @param  string  $index 要判断的下标
         * @return boolean        结果
         */
        public function __isset($index)
        {
            return isset($this->array[$index]);
        }
}

实现访问数组方式访问对象的属性

这里我们借助 ArrayAccess 这个接口

 再写一个抽象类,继承前面的抽象类并实现  `ArrayAccess` 接口的所有方法。
 这样我们就可以按照数组的形式访问对象了。
abstract class ArrayCommon extends BaseCommon implements  \ArrayAccess
{
        /** 
        * [字段是否存在] 
        * @param  [string] $index [字段名] 
        * @return [boolean]        [字段是否存在] 
        */  
        function offsetExists($index)  
        {  
           return isset($this->array[$index]);
        }

        /** 
        * [获取字段] 
        * @param  [string] $index [字段名] 
        * @return [string]        [字段值] 
        */  
        function offsetGet($index) {  
           return $this->array[$index];  
        }  
        /** 
        * [设置字段] 
        * @param  [string] $index    [字段名] 
        * @param  [string] $newvalue [字段值] 
        */  
        function offsetSet($index, $newvalue) {  
           $this->array[$index] = $newvalue;  
        }  
        /** 
        * [删除字段] 
        * @param  [string] $index [字段名] 
        */  
        function offsetUnset($index) {  
           unset($this->array[$index]);  
        } 
}

写在最后

这样从上面的最后一个抽象类 继承的类 就可以实现 既可以用对象方式访问有可以用数组方式访问了。

感觉少了点啥

万年之后 …… 终于想起来了。
怎么把数组再还原回来呢?

再弄一个抽象类 继承上面的抽象类

第一次写的时候忘了使用递归了,导致只能得到一层的还原数据

这样我们就把一个对象还原到原始的数组了。

代码:

abstract class newContinent extends ArrayCommon
{
        /**
         * 对象转换成数组
         * @return array 转换后的数组
         */
        public function toArray()
        {
            $arr = $this -> array;
            foreach ($arr as $k => $v) {
                if(is_object($v)){
                    $arr [$k] = $v -> toArray();
                    continue;
                }
            }
            return $arr;
        }
}

最最最后了

综合上面的代码 我们就能实现前面所说的所有的功能,并且任意一个级别的对象都会有 toArray 方法,自我感觉还是非常好用的。

完整示例

    abstract class CommonIterator implements  \Iterator,\ArrayAccess
    {
        protected $array;

        /**
         * 构造函数
         * @param Array $arr 要转换的数组
         */
        public function __construct(Array $arr)
        {
            $this -> array = $arr;
            foreach ($arr as $k => $v) {
                if(is_array($v)){
                    $this -> array [$k] = new static($v);
                    continue;
                }
                $this -> array [$k] = ($v);
            }
        }

        /**
         * 初始化数组时 调用的方法
         * @return [type] [description]
         */
        public function rewind()
        {
            return reset($this -> array);
        }

        /**
         * 检测 数组中键存不存在
         * @return [type] [description]
         */
        public function valid()
        {
            return array_key_exists($this -> key(), $this -> array);
        }

        /**
         * 获取当前数组指针指向的内容
         * @return mixed 指向的内容
         */
        public function current()
        {
            return current($this -> array);
        }

        /**
         * 获取指针指向的键
         * @return int|string 指针指向的键
         */
        public function key()
        {
            return key($this -> array);
        }

        /**
         * 使指针指向下一位
         * @return function [description]
         */
        public function next()
        {
            return next($this -> array);
        }

        /**
         * 对象魔术方法 当属性没有的时候或者属性私有的时候 触发这个方法
         * @param  string $name 属性名
         * @return mixed        返回的属性对应的值
         */
        public function __get($name)
        {
            if(isset($this -> array[$name]))
                return $this -> array[$name];
            return null;
        }

        /**
         * 判断对象属性存不存在
         * @param  string  $index 要判断的下标
         * @return boolean        结果
         */
        public function __isset($index)
        {
            return isset($this->array[$index]);
        }

        /**
         * 对象转换成数组
         * @return array 转换后的数组
         */
        public function toArray()
        {
            $arr = $this -> array;
            foreach ($arr as $k => $v) {
                if(is_object($v)){
                    $arr [$k] = $v -> toArray();
                    continue;
                }
            }
            return $arr;
        }
      
        /** 
        * [字段是否存在] 
        * @param  [string] $index [字段名] 
        * @return [boolean]        [字段是否存在] 
        */  
        function offsetExists($index)  
        {  
           return isset($this->array[$index]);
        }

        /** 
        * [获取字段] 
        * @param  [string] $index [字段名] 
        * @return [string]        [字段值] 
        */  
        function offsetGet($index) {  
           return $this->array[$index];  
        }  
        /** 
        * [设置字段] 
        * @param  [string] $index    [字段名] 
        * @param  [string] $newvalue [字段值] 
        */  
        function offsetSet($index, $newvalue) {  
           $this->array[$index] = $newvalue;  
        }  
        /** 
        * [删除字段] 
        * @param  [string] $index [字段名] 
        */  
        function offsetUnset($index) {  
           unset($this->array[$index]);  
        } 
    }
PREV
PHP 小白 学习 生成器接口(部分)
NEXT
打造自用 curl 类

评论(0)

评论已关闭