反射

反射

反射是一种动态获取类成员属性和成员方法,并且可以动态创建对象进行调用的一种技术。

Java语言有一个特别著名的框架叫Spring,几乎任何Java程序员对这个框架非常熟悉,这个框架早期最核心的思想就是DI(依赖注入),底层的技术实现核心就是依赖反射技术。

PHP本身其实不通过反射也能动态创建对象,通过new关键字就可以创建对象,如下例程:

<?php
namespace popo;

class User
{
    /**
     * @var string
     * @datetime 2020/7/1 9:20 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public $userName;

    /**
     * @var string
     * @datetime 2020/7/1 9:20 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public $password;
}


$class = 'popo\User';

$user = new $class();
$user->userName = 'reflect';

var_dump($user);

以上例程输出:

object(popo\User)#1 (2) {
  ["userName"]=>
  string(7) "reflect"
  ["password"]=>
  NULL
}

1. 反射扩展

PHP提供强大的反射库,绝大多数的开源框架都使用了反射扩展实现了DI,下面来介绍一下上面例程如何用反射去实现。

<?php
/**
 * Created by PhpStorm.
 * User: Jiang Haiqiang
 * Date: 2020/7/1
 * Time: 9:19 PM
 */
namespace popo;

class User
{
    /**
     * @var string
     * @datetime 2020/7/1 9:20 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public $userName;

    /**
     * @var string
     * @datetime 2020/7/1 9:20 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public $password;
}


$class = new \ReflectionClass('popo\User');
$user = $class->newInstance();
$user->userName = 'reflect';
var_dump($user);

以上例程输出:

object(popo\User)#2 (2) {
  ["userName"]=>
  string(7) "reflect"
  ["password"]=>
  NULL
}

从以上例程可以看出,PHP的反射非常简单,但是功能却十分强大。

1.1 反射获取类所有成员方法和属性

<?php
/**
 * Created by PhpStorm.
 * User: Jiang Haiqiang
 * Date: 2020/7/1
 * Time: 9:19 PM
 */
namespace popo;

class User
{
    /**
     * @var string
     * @datetime 2020/7/1 9:34 PM
     * @author roach
     * @email jhq0113@163.com
     */
    private $_salt = 'sdfas#$!@DDFSDF';

    /**
     * @var string
     * @datetime 2020/7/1 9:34 PM
     * @author roach
     * @email jhq0113@163.com
     */
    protected $_token;

    /**
     * @var string
     * @datetime 2020/7/1 9:20 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public $userName;

    /**
     * @var string
     * @datetime 2020/7/1 9:20 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public $password;

    /**
     * @param string $userId
     * @return string
     * @datetime 2020/7/1 9:35 PM
     * @author roach
     * @email jhq0113@163.com
     */
    private function _createToken($userId)
    {
        return hash_hmac('sha1', $this->_salt.$userId, $this->_salt);
    }

    /**
     * @param string $userId
     * @param string $token
     * @return bool
     * @datetime 2020/7/1 9:36 PM
     * @author roach
     * @email jhq0113@163.com
     */
    protected function _checkToken($userId, $token)
    {
        return $this->_createToken($userId) === $token;
    }

    /**
     * @return string
     * @datetime 2020/7/1 9:37 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public function getToken()
    {
        return $this->_token;
    }
}

$className = 'popo\User';
$class = new \ReflectionClass($className);

$properties = $class->getProperties();
foreach ($properties as $property) {
    /**
     * @var \ReflectionProperty $property
     */
    echo '类:'.$className.'拥有属性:'.$property->name
        .', private:'.$property->isPrivate()
        .', protected:'.$property->isProtected()
        .', public:'.$property->isPublic().PHP_EOL;
}

$methods = $class->getMethods();

foreach ($methods as $method) {
    /**
     * @var \ReflectionMethod $method
     */
    echo '类:'.$className.'拥有方法:'.$method->name
        .', private:'.$method->isPrivate()
        .', protected:'.$method->isProtected()
        .', public:'.$method->isPublic().PHP_EOL;
}

以上例程输出:

类:popo\User拥有方法:_createToken, private:1, protected:, public:
类:popo\User拥有方法:_checkToken, private:, protected:1, public:
类:popo\User拥有法:getToken, private:, protected:, public:1
类:popo\User拥有属性:_salt, private:1, protected:, public:
类:popo\User拥有属性:_token, private:, protected:1, public:
类:popo\User拥有属性:userName, private:, protected:, public:1
类:popo\User拥有属性:password, private:, protected:, public:1

通过以上例程我们可以看到,通过反射可以获取一个类的所有的成员属性和方法,同时能获取到属性和方法的访问权限。

我们通过调用\ReflectionClass实例的getProperties方法可以返回一个[]\ReflectionProperty,通过\ReflectionProperty我们可以获取属性的所有信息而无需真正的创建实例,包括注释。

我们通过调用\ReflectionClass实例的getMethods方法可以返回一个[]\ReflectionMethod,通过\ReflectionMethod我们可以获取属性的所有信息而无需真正的创建实例,包括注释。

1.2 通过反射调用构造函数实例化对象

<?php
/**
 * Created by PhpStorm.
 * User: Jiang Haiqiang
 * Date: 2020/7/1
 * Time: 9:19 PM
 */
namespace popo;

/**
 * Class Product
 * @package popo
 * @datetime 2020/7/1 10:11 PM
 * @author roach
 * @email jhq0113@163.com
 */
class Product
{
    /**
     * @var string
     * @datetime 2020/7/1 10:04 PM
     * @author roach
     * @email jhq0113@163.com
     */
    protected $_name;

    /**
     * @var float
     * @datetime 2020/7/1 10:04 PM
     * @author roach
     * @email jhq0113@163.com
     */
    protected $_price;

    /**
     * Product constructor.
     * @param string $name
     * @param float  $price
     */
    public function __construct($name, $price)
    {
        $this->_name  = $name;
        $this->_price = $price;
    }

    /**
     * @return string
     * @datetime 2020/7/1 10:05 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public function getName()
    {
        return $this->_name;
    }

    /**
     * @return float
     * @datetime 2020/7/1 10:05 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public function getPrice()
    {
        return $this->_price;
    }
}

$className = 'popo\Product';
$class = new \ReflectionClass($className);
$product = $class->newInstanceArgs(['PHP进阶教程', 99.99]);

var_dump($product);

以上例程输出:

object(popo\Product)#2 (2) {
  ["_name":protected]=>
  string(15) "PHP进阶教程"
  ["_price":protected]=>
  float(99.99)
}

1.3 通用反射创建对象

通过以上案例我们可以通过反射调用构造函数创建并初始化对象了,但是有一点不足,不够通用。

实际开发中习惯定义一个基类,构造函数参数只有一个数组,通过数组参数装配对象,这样反射创建对象的时候通过数组配置就可以创建,如下:

<?php
/**
 * Created by PhpStorm.
 * User: Jiang Haiqiang
 * Date: 2020/7/1
 * Time: 9:19 PM
 */
namespace popo;

/**
 * Class BaseObject
 * @package popo
 * @datetime 2020/7/1 10:11 PM
 * @author roach
 * @email jhq0113@163.com
 */
class BaseObject
{
    /**
     * BaseObject constructor.
     * @param array $properties
     */
    public function __construct($properties = [])
    {
        foreach ($properties as $property => $value) {
            if(property_exists($this, $property)) {
                $this->$property = $value;
            }
        }
    }
}

/**
 * Class Product
 * @package popo
 * @datetime 2020/7/1 10:11 PM
 * @author roach
 * @email jhq0113@163.com
 */
class Product extends BaseObject
{
    /**
     * @var string
     * @datetime 2020/7/1 10:04 PM
     * @author roach
     * @email jhq0113@163.com
     */
    protected $_name;

    /**
     * @var float
     * @datetime 2020/7/1 10:04 PM
     * @author roach
     * @email jhq0113@163.com
     */
    protected $_price;


    /**
     * @return string
     * @datetime 2020/7/1 10:05 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public function getName()
    {
        return $this->_name;
    }

    /**
     * @return float
     * @datetime 2020/7/1 10:05 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public function getPrice()
    {
        return $this->_price;
    }
}

$className = 'popo\Product';
$class = new \ReflectionClass($className);
$product = $class->newInstanceArgs([
    [
        '_name' => 'PHP进阶教程',
        '_price' => 99.99
    ]
]);
var_dump($product);

以上例程输出:

object(popo\Product)#2 (2) {
  ["_name":protected]=>
  string(15) "PHP进阶教程"
  ["_price":protected]=>
  float(99.99)
}

好了,关于反射我们就学习到这里了,反射还有好多强大的功能等着大家去探索,自己动手试试吧。

学习更多内容: https://404.360tryst.com

我的视频课程: https://edu.csdn.net/course/detail/9933

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苍穹0113

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值