PHP利用反射数组转类

一、简述

  • 这里使用反射类ReflectionClass,主要是解析类属性注释中的@var,支持l类和类数组形式,满足了大部分的需求
  • 目前只对@var进行解析,在抽象类Attribute中预留对其他注释的解析,只需继承Attribute类,实现对应的initializeinvoke方法。

二、代码

  • Attribute类:抽象类,所有注释解析都需继承这个类,实现对应的方法
<?php
namespace App\Services\Reflection;


abstract class Attribute
{
    /**
     * 对不同注释进行解析,例如@var,@auth等
     * @param $value
     * @return mixed
     */
    public abstract function initialize($value);

    /**
     * 执行某个的对象的目标方法或者返回类属性对应的修饰类
     * @return mixed
     */
    public abstract function invoke();

    /**
     * 工厂返回不同的解析类
     * @param AttributeInfo $info
     * @return VariableAttribute|null
     */
    public static function createFromAttributeInfo(AttributeInfo $info)
    {
        //目前先解析@var的注释作
        switch (strtolower($info->type)) {
            case 'var':
                $attribute = new VariableAttribute();
                break;

        }
        if (isset($attribute)) {
            $attribute->initialize($info->value);
            return $attribute;
        }
        return null;
    }
}
  • AttributeInfo类:解析注释类,正则表达式拆分,拆分成如[['type' => 'var', 'value' => 'class']],里面是对象AttributeInfo对象
<?php
namespace App\Services\Reflection;


class AttributeInfo
{

    public $type;

    public $value;

    public function __construct($type, $value=null)
    {
        $this->type = $type;
        $this->value = $value;
    }

    /**
     * 解析注释
     * @param $comment
     * @return array|null
     */
    public static function create($comment)
    {
        // 正则表达式拆分,拆分成如[['type' => 'var', 'value' => 'class']],里面是对象AttributeInfo对象
        $regex = '#@(?<type>[a-zA-Z][a-zA-Z0-9\_]+)([ ]+(?<value>.*))?#i';
        if (preg_match_all($regex, $comment, $matches, PREG_SET_ORDER)) {
            $attributes = [];
            foreach ($matches as $match) {
                $type = isset($match['type']) ? $match['type'] : null;
                if (isset($type)) {
                    $value = isset($match['value']) ? $match['value'] : null;
                    $attributes[] = new AttributeInfo($type, trim($value));
                }
            }
            return $attributes;
        }
        return null;
    }
}
  • AttributeCollection类:类属性集合
<?php

namespace App\Services\Reflection;


class AttributeCollection
{

    private $attributes;

    private function __construct(){}

    public static function create($comment)
    {
        $attributes = AttributeInfo::create($comment);
        $collection = new AttributeCollection();
        if (isset($attributes)) {
            foreach ($attributes as $info) {
                $attribute = Attribute::createFromAttributeInfo($info);
                if (isset($attribute)) {
                    $collection->attributes[] = $attribute;
                }
            }
        }
        return $collection;
    }

    public function invoke()
    {
        if (!empty($this->attributes)) {
            /** @var Attribute $attribute */
            foreach ($this->attributes as $attribute) {
                $attribute->invoke();
            }
        }
    }

    public function exists($class)
    {
        if (!empty($this->attributes)) {
            foreach ($this->attributes as $attribute) {
                if ($class === get_class($attribute)) {
                    return true;
                }
            }
        }
        return false;
    }

    public function attributes($class = null)
    {
        if (empty($this->attributes)) {
            return null;
        }

        $attributes = array();
        foreach ($this->attributes as $attribute) {
            if ($class === get_class($attribute)) {
                $attributes[] = $attribute;
            }
        }

        return $this->attributes;
    }
}
  • VariableAttribute类:@var注释解析
<?php

namespace App\Services\Reflection;


class VariableAttribute extends Attribute
{

    private $class;

    private $isArray = false;

    public function initialize($value)
    {
        // 这里有两种情况:
        // ①类,即@var className
        // ②类数组, 即@var className[]
        $regex = '#^(?<class>[\\\\\/]?[a-zA-Z][a-zA-Z\_0-9\\\\\/]*)(?<digit>\[\])?#i';
        if (preg_match($regex, $value, $match)) {
            $this->class = $match['class'];
            $this->isArray = array_key_exists('digit', $match);
        }
    }

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

    public function isClass()
    {
        // 这里排除变量类型
        $classes = ["string", "double", "float", "long", "int", "integer", "bool", "boolean", "resource", "array"];
        return isset($this->class) && false === array_search(strtolower($this->class), $classes);
    }

    public function invoke()
    {
        return $this->class;
    }
}
  • Json类:将json字符串转成类
<?php

namespace App\Services\Reflection;



class Json
{

    /**
     * json转类
     * @param $arg
     * @param $class
     * @return null
     */
    public static function toObject($arg, $class)
    {
        try {
            if (is_string($class)) {
                $class = new \ReflectionClass($class);
            }
            $params = $arg;
            if (is_string($arg) && !is_array($arg)) {
                $params = self::toArray($arg);
            }
            if (!empty($params)) {
                $object = new $class->name;
                $properties = $class->getProperties();
                if (!empty($properties)) {
                    foreach ($properties as $property) {
                        if (array_key_exists($property->name, $params)) {
                            $value = $params[$property->name];
                            $attributes = AttributeCollection::create($property->getDocComment())
                                ->attributes(VariableAttribute::class);
                            if (isset($attributes[0]) && !empty($attributes[0])) {
                                /** @var VariableAttribute $attribute */
                                $attribute = $attributes[0];
                                $class = $attribute->invoke();
                                if ($attribute->isClass() && isset($class)) {
                                    if ($attribute->isArray()) {
                                        $value = self::toArray($value, $class);
                                    } else {
                                        $value = self::toObject($value, $class);
                                    }
                                }
                            }
                            $property->setValue($object, $value);
                        }
                    }
                }
                return $object;
            }
            return null;
        } catch (\ReflectionException $exception) {
            return null;
        }
    }

    /**
     * json转数据
     * @param $arg
     * @param null $class
     * @return array|mixed|string
     */
    public static function toArray($arg, $class=null)
    {
        if (is_string($arg) && !is_array($arg)) {
            $list = json_decode($arg, true);
        } else {
            $list = $arg;
        }

        if (isset($class)) {
            $result = array();
            if (is_array($list) && !empty($list)) {
                foreach ($list as $item) {
                    $result[] = self::toObject($item, $class);
                }
            }
            return $result;
        }
        return $list;
    }
}

三、测试

<?php

namespace App\Services\Test;


class A
{

    public $a1;

    public $a2;

}

<?php

namespace App\Services\Test;


class B
{

    public $b1;

    public $b2;

    /**
     * @var \App\Services\Test\A
     */
    public $a;

}

<?php

namespace App\Services\Test;


class C
{

    public $c1;

    public $c2;

    /**
     * @var \App\Services\Test\A[]
     */
    public $a;

    /** @var  \App\Services\Test\B */
    public $b;
}

<?php

namespace App\Http\Controllers\Api\V1;


use App\Http\Controllers\ApiController;
use App\Services\Reflection\Json;
use App\Services\Test\C;

class TestController extends ApiController
{

    public function index()
    {
        $data = [
            'c1' => 1,
            'c2' => 2,
            'a' => [
                ['a1' => 3, 'a2' => 4],
                ['a1' => 5, 'a2' => 6],
            ],
            'b' => [
                'b1' => 7,
                'b2' => 8,
                'a' => ['a1' => 9, 'a2' => 10]
            ],
        ];
        $dataJson = json_encode($data, JSON_UNESCAPED_UNICODE);
        $parse = Json::toObject($dataJson, C::class);
        dd($parse);die;
    }
}

执行结果如下:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值