php反射学习之不用new方法实例化类操作示例


Posted in PHP onJune 14, 2019

本文实例讲述了php反射学习之不用new方法实例化类操作。分享给大家供大家参考,具体如下:

上一篇php反射入门示例简单介绍了 php 反射的几个常见类的使用方法,但是用反射能做些什么,你可能还是想象不到,

下面我稍微应用反射类来做点东西,大家知道实例化一个类需要用new 关键字,不用 new 可以吗?答案是可以的,用反射就能实现:

首先创建一个文件 student.php:

<?php
class Student
{
  public $id;
  public $name;
  public function __construct($id,$name)
  {
    $this->id = $id;
    $this->name = $name;
  }
  public function study()
  {
    echo $this->name.' is learning.....'.PHP_EOL;
  }
  public function showBag(){
    echo "My bag have ".$this->bag->all();
  }
}

另新建一个文件run.php

<?php
require 'student.php';
function make($class, $vars = []) {
  $ref = new ReflectionClass($class);
  if(!$ref->isInstantiable()) {
    throw new Exception("类{$class} 不存在");
  }
  $constructor = $ref->getConstructor();
  if(is_null($constructor)) {
    return new $class;
  }
  $params = $constructor->getParameters();
  $resolveParams = [];
  foreach ($params as $key=>$value) {
    $name = $value->getName();
    if(isset($vars[$name])) {
      $resolveParams[] = $vars[$name];
    } else {
      $default = $value->isDefaultValueAvailable() ? $value->getDefaultValue() : null;
      if(is_null($default)) {
        if($value->getClass()) {
          $resolveParams[] = make($value->getClass()->getName(), $vars);
        } else {
          throw new Exception("{$name} 没有传值且没有默认值。");
        }
      } else {
        $resolveParams[] = $default;
      }
    }
  }
  return $ref->newInstanceArgs($resolveParams);
}

run.php 中make 函数就是我们用来实例化类而编写的函数,第一个参数传入类名,第二个参数是类的构造函数需要传入的参数数据。

根据 Student 的构造函数的参数不同有几种情况:(以下代码,请按不同情况追加到 run.php 中运行)

情况一: 没有提供 $name 的值

try {
  $stu = make('Student', ['id' => 1]);
  print_r($stu);
  $stu->study();
} catch (Exception $e) {
  echo $e->getMessage();
}

在构造函数中$name 没有默认值时,情况一会报错, 你可以稍微修改下 Student类,给 $name 提供一个默认值,这时候就不会报错了。

情况二 提供了 $name 的值

try {
  $stu = make('Student', ['id' => 1, 'name' => 'li']);
  print_r($stu);
  $stu->study();
} catch (Exception $e) {
  echo $e->getMessage();
}

情况三,我们把 student.php 改一下

<?php
class Bag{
  public function name(){
    return "学生包".PHP_EOL;
  }
}
class Student
{
  public $id;
  public $name;
  public function __construct($id, $name="xxx", Bag $bag)
  {
    $this->id = $id;
    $this->name = $name;
    $this->bag = $bag;
  }
  public function study()
  {
    echo $this->name.' is learning.....'.PHP_EOL;
  }
  public function showBag(){
    echo "My bag is ".$this->bag->name();
  }
}

可以看到,给 Student 类加了一个参数$bag, 类型 是 Bag

这时候运行一下

<?php
try {
  $stu = make('Student', ['id' => 1, 'name' => 'li']);
  print_r($stu);
  $stu->study();
  $stu->showBag();
} catch (Exception $e) {
  echo $e->getMessage();
}

可以看到构造函数的第三个参数 $bag ,被自动实例化了,然后传递给了 Student 类的构造函数,这个部分很关键,这个地方可以用来实现依赖注入,我们不必在手动实例化对象了,我们可以根据参数的对应的类来自动实例化对象,从而实现类之间的解耦。如果你学过 Laravel的话,你应该对这个很熟悉了。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP.MVC的模板标签系统(四)
Sep 05 PHP
php实现mysql数据库备份类
Mar 20 PHP
php输出xml格式字符串(用的这个)
Jul 12 PHP
PHP读取文件并可支持远程文件的代码分享
Oct 03 PHP
PHP无限分类(树形类)
Sep 28 PHP
JavaScript实现滚动栏效果的方法
Apr 27 PHP
浅谈PHP中foreach/in_array的使用
Nov 02 PHP
PHP实现QQ快速登录的方法
Sep 28 PHP
PHP基于回溯算法解决n皇后问题的方法示例
Nov 07 PHP
PHP实现求连续子数组最大和问题2种解决方法
Dec 26 PHP
PHP使用Redis长连接的方法详解
Feb 12 PHP
PhpStorm 如何优雅的调试Hyperf的方法步骤
Nov 24 PHP
PHP反射学习入门示例
Jun 14 #PHP
PHP如何实现阿里云短信sdk灵活应用在项目中的方法
Jun 14 #PHP
PHP中常用的三种设计模式详解【单例模式、工厂模式、观察者模式】
Jun 14 #PHP
PHP面向对象程序设计子类扩展父类(子类重新载入父类)操作详解
Jun 14 #PHP
PHP面向对象程序设计模拟一般面向对象语言中的方法重载(overload)示例
Jun 13 #PHP
PHP面向对象程序设计重载(overloading)操作详解
Jun 13 #PHP
PHP面向对象程序设计之构造方法和析构方法详解
Jun 13 #PHP
You might like
透析PHP的配置文件php.ini
2006/10/09 PHP
使用php实现快钱支付功能(涉及到接口)
2013/07/01 PHP
php pdo oracle中文乱码的快速解决方法
2016/05/16 PHP
利用PHP命令行模式采集股票趋势信息
2016/08/09 PHP
php实现简易计算器
2020/08/28 PHP
利用JS进行图片的切换即特效展示图片
2013/12/03 Javascript
详解JavaScript设计模式开发中的桥接模式使用
2016/05/18 Javascript
详谈js中window.location.search的用法和作用
2017/02/13 Javascript
React-router中结合webpack实现按需加载实例
2017/05/25 Javascript
关于webpack代码拆分的解析
2017/07/20 Javascript
js对象实例详解(JavaScript对象深度剖析,深度理解js对象)
2017/09/21 Javascript
详解从Vue.js源码看异步更新DOM策略及nextTick
2017/10/11 Javascript
Vue路由history模式解决404问题的几种方法
2018/09/29 Javascript
深入理解Angularjs 脏值检测
2018/10/12 Javascript
Vue结合路由配置递归实现菜单栏功能
2020/06/16 Javascript
Python实现查找系统盘中需要找的字符
2015/07/14 Python
Python中内建函数的简单用法说明
2016/05/05 Python
python结合selenium获取XX省交通违章数据的实现思路及代码
2016/06/26 Python
Python机器学习之决策树算法
2017/12/22 Python
tensorflow建立一个简单的神经网络的方法
2018/02/10 Python
python 二维数组90度旋转的方法
2019/01/28 Python
python GUI实现小球满屏乱跑效果
2019/05/09 Python
python自动化UI工具发送QQ消息的实例
2019/08/27 Python
git查看、创建、删除、本地、远程分支方法详解
2020/02/18 Python
详解Python中的路径问题
2020/09/02 Python
python 获取谷歌浏览器保存的密码
2021/01/06 Python
HTML5本地存储之IndexedDB
2017/06/16 HTML / CSS
阿玛尼美妆加拿大官方商城:Giorgio Armani Beauty加拿大
2017/10/24 全球购物
购买英国原创艺术:Art Gallery
2018/08/25 全球购物
英国户外服装、鞋类和设备的领先零售商:Millets
2020/10/12 全球购物
销售提升方案
2014/06/07 职场文书
基层党建工作宣传标语
2014/06/24 职场文书
学习走群众路线心得体会
2014/11/05 职场文书
党员自评材料范文
2014/12/17 职场文书
小学英语复习计划
2015/01/19 职场文书
合同纠纷调解书
2015/05/20 职场文书