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 相关文章推荐
Win2003服务器安全加固设置--进一步提高服务器安全性
May 23 PHP
php zend 相对路径问题
Jan 12 PHP
基于OpenCV的PHP图像人脸识别技术
Oct 11 PHP
一步一步学习PHP(4) php 函数 补充2
Feb 15 PHP
php eval函数用法总结
Oct 31 PHP
更改localhost为其他名字的方法
Feb 10 PHP
thinkphp区间查询、统计查询与SQL直接查询实例分析
Nov 24 PHP
php5.4以下版本json不支持不转义内容中文的解决方法
Jan 13 PHP
PHP实现批量生成App各种尺寸Logo
Mar 19 PHP
PHP使用递归方式列出当前目录下所有文件的方法
Jun 02 PHP
PHP购物车类Cart.class.php定义与用法示例
Jul 20 PHP
thinkPHP5.1框架路由::get、post请求简单用法示例
May 06 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
解决MySQL中文输出变成问号的问题
2008/06/05 PHP
Fatal error: Call to undefined function curl_init()解决方法
2010/04/09 PHP
PHP执行linux系统命令的常用函数使用说明
2010/04/27 PHP
关于file_get_contents返回为空或函数不可用的解决方案
2013/06/24 PHP
PHP中curl_setopt函数用法实例分析
2015/04/16 PHP
Yii配置与使用memcached缓存的方法
2016/07/13 PHP
PHP实现的策略模式示例
2019/03/20 PHP
一些Javascript的IE和Firefox(火狐)兼容性的问题总结及常用例子
2009/05/21 Javascript
!DOCTYPE声明对JavaScript的影响分析
2010/04/12 Javascript
js字符串的各种格式的转换 ToString,Format
2011/08/08 Javascript
jQuery读取和设定KindEditor值的方法
2013/11/22 Javascript
jquery检测input checked 控件是否被选中的方法
2014/03/26 Javascript
jQuery实现延迟跳转的方法
2015/06/05 Javascript
使用JavaScript实现连续滚动字幕效果的方法
2015/07/07 Javascript
js修改onclick动作的四种方法(推荐)
2016/08/18 Javascript
jQuery实现选中行变色效果(实例讲解)
2017/07/06 jQuery
推荐VSCode 上特别好用的 Vue 插件之vetur
2017/09/14 Javascript
微信小程序实现手指拖动选项排序
2020/04/22 Javascript
js实现拖拽元素选择和删除
2020/08/25 Javascript
Python网络爬虫实例讲解
2016/04/28 Python
python处理html转义字符的方法详解
2016/07/01 Python
Python标准库sched模块使用指南
2017/07/06 Python
用什么库写 Python 命令行程序(示例代码详解)
2020/02/20 Python
Django中使用Json返回数据的实现方法
2020/06/03 Python
前端使用canvas生成盲水印的加密解密的实现
2020/12/16 HTML / CSS
Notino瑞典:购买香水和美容产品
2019/07/26 全球购物
初中生三年学习生活的自我评价
2013/11/03 职场文书
模具设计与制造专业推荐信
2014/02/16 职场文书
宣传口号大全
2014/06/16 职场文书
小学语文教研活动总结
2014/07/01 职场文书
三严三实学习心得体会(精选N篇)
2016/01/05 职场文书
2016入党积极分子心得体会
2016/01/06 职场文书
Python爬取英雄联盟MSI直播间弹幕并生成词云图
2021/06/01 Python
关于Numpy之repeat、tile的用法总结
2021/06/02 Python
go语言中http超时引发的事故解决
2021/06/02 Golang
Mysql中where与on的区别及何时使用详析
2021/08/04 MySQL