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 相关文章推荐
几种显示数据的方法的比较
Oct 09 PHP
PHP中::、-&amp;gt;、self、$this几种操作符的区别介绍
Apr 24 PHP
PHP整合PayPal支付
Jun 11 PHP
WordPress中邮件的一些修改和自定义技巧
Dec 15 PHP
无需数据库在线投票调查php代码
Jul 20 PHP
浅谈PHP拦截器之__set()与__get()的理解与使用方法
Oct 18 PHP
PHP静态成员变量和非静态成员变量详解
Feb 14 PHP
PHP空值检测函数与方法汇总
Nov 19 PHP
PHP实现随机数字、字母的验证码功能
Aug 01 PHP
Laravel框架实现修改登录和注册接口数据返回格式的方法
Aug 17 PHP
ThinkPHP5.1框架数据库链接和增删改查操作示例
Aug 03 PHP
laravel 创建命令行命令的图文教程
Oct 23 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
mysql5详细安装教程
2007/01/15 PHP
ThinkPHP3.0略缩图不能保存到子目录的解决方法
2012/09/30 PHP
php使用异或实现的加密解密实例
2013/09/04 PHP
php中time()与$_SERVER[REQUEST_TIME]用法区别
2014/11/19 PHP
Zend Framework教程之资源(Resources)用法实例详解
2016/03/14 PHP
PHP定义字符串的四种方式详解
2018/02/06 PHP
PHP实现微信退款的方法示例
2019/03/26 PHP
JavaScript中Array 对象相关的几个方法
2006/12/22 Javascript
jquery之Document元素选择器篇
2008/08/14 Javascript
JavaScript去掉数组中的重复元素
2011/01/13 Javascript
jQuery Tools Dateinput使用介绍
2012/07/14 Javascript
基于jquery实现的定时显示与隐藏div广告的实现代码
2013/08/22 Javascript
Javascript中克隆一个数组的实现代码
2013/12/06 Javascript
window resize和scroll事件的基本优化思路
2014/04/29 Javascript
javascript判断移动端访问设备并解析对应CSS的方法
2015/02/05 Javascript
关于json字符串与实体之间的严格验证代码
2016/11/10 Javascript
详解angularjs popup-table 弹出框表格指令
2017/09/20 Javascript
javascript中神奇的 Date对象小结
2017/10/12 Javascript
JS实现的按钮点击颜色切换功能示例
2017/10/19 Javascript
JS使用tofixed与round处理数据四舍五入的区别
2017/10/25 Javascript
vue中父子组件注意事项,传值及slot应用技巧
2018/05/09 Javascript
npm 更改默认全局路径以及国内镜像的方法
2018/05/16 Javascript
JS闭包原理及其使用场景解析
2020/12/03 Javascript
python使用any判断一个对象是否为空的方法
2014/11/19 Python
Python中使用ElementTree解析XML示例
2015/06/02 Python
Python脚本实现12306火车票查询系统
2016/09/30 Python
Python简单实现控制电脑的方法
2018/01/22 Python
Python求出0~100以内的所有素数
2018/01/23 Python
python 3.6.5 安装配置方法图文教程
2018/09/18 Python
Spring Cloud Feign高级应用实例详解
2019/12/10 Python
python 写一个水果忍者游戏
2021/01/13 Python
shallow copy和deep copy的区别
2016/05/09 面试题
初一新生军训方案
2014/05/22 职场文书
2014年酒店前台工作总结
2014/11/14 职场文书
三下乡个人总结
2015/03/04 职场文书
2016年优秀共青团员事迹材料
2016/02/25 职场文书