PHP依赖注入实现二

文章描述了在使用TP5.0框架时遇到的问题,具体是在调用invokeClass方法时,由于构造函数参数设置不当导致的错误。作者最初误认为是框架源码问题,后来发现是自己的参数传递错误。通过调整构造函数参数,问题得到解决。文章展示了框架中反射和依赖注入的使用,并给出了相关的代码示例。
摘要由CSDN通过智能技术生成

公司用的tp5.0,意外发现有现成的代码。

类名:think/App  文件名:/thinkphp/library/think/App.php  方法名:invokeClass

invokeClass这个方法根据构造参数是否为类处理,若为类则调用类的静态方法invoke或instance,获取类的实例。该方法可设置参数。

我第一次使用时报错,因为我设置的构造有两个参数,第一个设置类的类型,第二个没设置,传递参数的时候为第一个是实例,第二个是整数,返回处理过的参数为两个实例,正确的化应该是一个实例一个整数

就是因为第一个参数被当作类处理,没有使用传递的参数,而第二次设置值时使用第一个参数,用array_shift(传递的构造参数)获取和修改传递的构造参数,也就是传递的第二个参数一直没被使用。

一开始以为是源码的问题,所以另写一个类继承之后再改。改完调通,觉得自己多此一举。

既然一开始自己就想用设置好的实例作为参数,构造里不设置类的类型就好。再改代码,果然如此。

tp5.0代码如下

 /**
     * 调用反射执行类的实例化 支持依赖注入
     * @access public
     * @param string $class 类名
     * @param array  $vars  变量
     * @return mixed
     */
    public static function invokeClass($class, $vars = [])
    {
        $reflect = new \ReflectionClass($class);
        $constructor = $reflect->getConstructor();
        $args = $constructor ? self::bindParams($constructor, $vars) : [];
        return $reflect->newInstanceArgs($args);
    }

    /**
     * 绑定参数
     * @access private
     * @param \ReflectionMethod|\ReflectionFunction $reflect 反射类
     * @param array                                 $vars    变量
     * @return array
     */
    private static function bindParams($reflect, $vars = [])
    {
        // 自动获取请求变量
        if (empty($vars)) {
            $vars = Config::get('url_param_type') ?
            Request::instance()->route() :
            Request::instance()->param();
        }

        $args = [];
        if ($reflect->getNumberOfParameters() > 0) {
            // 判断数组类型 数字数组时按顺序绑定参数
            reset($vars);
            $type = key($vars) === 0 ? 1 : 0;

            foreach ($reflect->getParameters() as $param) {
                $args[] = self::getParamValue($param, $vars, $type);
            }
        }

        return $args;
    }

    /**
     * 获取参数值
     * @access private
     * @param \ReflectionParameter  $param 参数
     * @param array                 $vars  变量
     * @param string                $type  类别
     * @return array
     */
    private static function getParamValue($param, &$vars, $type)
    {
        $name = $param->getName();
        $class = $param->getClass();

        if ($class) {
            $className = $class->getName();
            $bind = Request::instance()->$name;

            if ($bind instanceof $className) {
                $result = $bind;
            } else {
                if (method_exists($className, 'invoke')) {
                    $method = new \ReflectionMethod($className, 'invoke');

                    if ($method->isPublic() && $method->isStatic()) {
                        return $className::invoke(Request::instance());
                    }
                }

                $result = method_exists($className, 'instance') ?
                $className::instance() :
                new $className;
            }
        } elseif (1 == $type && !empty($vars)) {
            $result = array_shift($vars);
        } elseif (0 == $type && isset($vars[$name])) {
            $result = $vars[$name];
        } elseif ($param->isDefaultValueAvailable()) {
            $result = $param->getDefaultValue();
        } else {
            throw new \InvalidArgumentException('method param miss:' . $name);
        }

        return $result;
    }

使用代码如下

//基础类
<?php

namespace app\index\server\finance\hireorder;

use app\index\model\enterprisemodel;

class Enterprise
{
    private $fsinfo;
    private $einfo;
    public function __construct($fsinfo, $accountid)
    {
        $this->fsinfo = $fsinfo;
        $this->setaccount($accountid);
    }
    private function setaccount($accountid)
    {
        var_dump($accountid);exit;
    }
}

<?php

namespace app\index\server\finance;

use app\index\model\financesubjectmodel;
use think\App;

class Enterprise
{
    private $allowmodelkey = ['hireorder'];
    private $modelkey;
    private $fsinfo;

    public function __construct(financesubjectmodel $fsinfo)
    {
        $modelkey = $fsinfo['model_key'];
        $this->modelkey = $modelkey;
        $this->fsinfo = $fsinfo;
    }
    public function getclass($accountid)
    {
        $class = __CLASS__;
        $class = explode('\\', $class);
        $class[count($class) - 1] = $this->modelkey . "\\" . $class[count($class) - 1];
        $classname = join('\\', $class);
        $param = [
            $this->fsinfo,
            $accountid,
        ];
        $obj = App::invokeClass($classname, $param);
        return $obj;
    }
}
<?php

namespace app\index\server;

use app\index\model\financesubjectmodel;
use app\index\server\finance\Enterprise;
use app\index\server\finance\Platform;
use app\index\server\finance\User;

class financesubjectserver
{
    private $fsinfo;
    private $accountid;
    public function __construct($subjectkey, $accountid)
    {
        $m_fs = new financesubjectmodel();
        $fsinfo = $m_fs->getInfo(['subject_use_key' => $subjectkey, 'status' => 1]);
        $this->fsinfo = $fsinfo;
        $this->accountid = $accountid;
    }
    public function getclass()
    {
        $fsinfo = $this->fsinfo;
        $accountid = $this->accountid;
        $s_obj = new Enterprise($fsinfo);
        $s_obj = $s_obj->getclass($accountid);
        return $s_obj;
    }
}

//测试
use app\index\server\financesubjectserver;
class Test extends Controller
{
  public function financeserver()
    {
        echo "<pre>";
        $useobj = new financesubjectserver('enterprise_personal_tax', 12);
        $useobj = $useobj->getclass();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lsswear

感谢大佬打赏 q(≧▽≦q)

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

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

打赏作者

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

抵扣说明:

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

余额充值