相关文章推荐
道上混的甜瓜  ·  MySQL ...·  1 年前    · 
胡子拉碴的大葱  ·  java ...·  1 年前    · 
没读研的大葱  ·  springboot 中 ...·  1 年前    · 

实现原理: 在基类中定义一个公共的调用函数,这里我定义函数名为 handleAction handleAction 函数要实现的功能是首先获取调用该函数的子类名称,然后得到子类的实例,最后约定请求某一接口时,通过传参 handle=要调用的接口函数名 ,即可实现接口请求的自动分发了。

在实现之前,我们需要先对PHP中 __CLASS__ get_class() get_called_class() 的使用和区别有一定的了解。

我们知道,PHP中可以通过 __CLASS__ 可以获取当前的类名,但它是静态绑定的,在子类调用,如果继承了父类,那所得到的依旧是父类的名称,而不是子类的名称,比如:

class Base { function __construct ( ) { echo __CLASS__ ; static function getClass ( ) { echo __CLASS__ ; class Child extends Base { $child = new Child (); // 输出 Base child:: getClass (); // 还是输出 Base

此时,无论将子类实例化还是直接调用静态方法,得到的都是父类的名称。如果是想得到子类的名称呢,那该如何实现?

这里就要通过PHP自带其他两个函数 get_class() get_called_class() 来解决这个问题:

  • get_class() 用于实例调用,加入参数 $this 可解决子类继承调用的问题;
  • get_called_class() 则是用于静态方法调用,获取当前主调类的类名。
  • 注意: get_called_class() 需要 PHP>=5.3.0 才支持,可查看 官方手册

    所以还是刚才的例子:

    class Base { function __construct ( ) { // echo get_class(); // 不加 $this 参数时,它返回的是当前的类名,即 Base echo get_class ( $this ); // 加了 $this 参数后,它返回是当前实例化的那个类名,即 Child static function getClass ( ) { echo get_called_class (); class Child extends Base { $child = new Child (); // 输出 Child child:: getClass (); // 输出 Child

    最终得到了我们想要的结果,即在父类中获取当前调用父类函数的子类类名。 了解了这些,接下来开始实现我们题目说的功能。

    1、首先,为了减少多次new带来的资源消耗,我们要使用单例模式

    在基类中,定义实现单例模式的方法,然后在继承它的子类中调用:

    class Base {
    	private static $instance = array();
         * 单例模式
    	static function getInstance() {
       		$className = get_called_class();
       		if (isset(self::$instance[$className])) {
            	return self::$instance[$className];
       		self::$instance[$className] = new $className;
       		return self::$instance[$className];
    class Child extends Base {
    $child = Child::getInstance();    // 子类实例
    

    通过以上实现,就可以得到子类 child 的单例实例了,如果有更多的子类,通过以上实现也可以得到对应子类的单例实例,而不用在每个子类中重复声明单例实现方法,是不是很方便呢。

    2、实现自动分发调用对应类中的接口函数

    其实开头已经说过,实现起来不难,就是根据接口请求时的传参,然后根据传参值,自动分发调用当前类中的对应接口函数:

    class Base {
    	private static $instance = array();
         * 单例模式
    	static function getInstance() {
       		$className = get_called_class();
       		if (isset(self::$instance[$className])) {
            	return self::$instance[$className];
       		self::$instance[$className] = new $className;
       		return self::$instance[$className];
         * 根据请求接口时传参,自动分发调用对应类实例中的可执行函数
        static function handleAction()
            $handleFunction = $_REQUEST['handle']; //  请求传参:handle=要调用的接口函数名,handle参数名可自行定义
            $instance = self::getInstance(); // 获取当前类调用 handleAction() 的单例
            $currClassName = get_class($instance); // 根据实例获取当前类名
            if (is_callable($currClassName, $handleFunction)) { // 判断 $handleFunction 函数在当前类中是否可调用
                echo $instance->$handleFunction();
            } else {
                echo "Error: Method '" . $handleFunction . "' of class '" . $currClassName . "' does not exist!";
    class ChildA extends Base {
    	function getInfo() {
    		echo 'This is ChildA';
    	... // 其他方法
    class ChildB extends Base {
    	function getInfo() {
    		echo 'This is ChildB';
    	... // 其他方法
    

    然后在接口中引用: 接口文件A A.php

    require_once 'Base父类文件'; require_once 'ChildA子类文件'; // 当然以上你可以使用 spl_autoload_register 实现类的自动加载,此处只为了演示,就不作实现了。 ChildA::handleAction();

    接口文件B B.php 同上。

    最后你就可以调用接口时,不管是 get 还是 post 请求,只需带上参数 handle=要调用的接口函数名 即可调用对应子类中的接口函数:

    // 示例
    requireUrl: 
    	server/api/A.php?handle=getInfo
    	server/api/B.php?handle=getInfo
    	// server/api/B.php?handle=其他方法名
    // 结果:
    This is ChildA
    This is ChildB
    

    以上即可实现通过简洁的代码,将请求自动分发到对应类的接口函数了,是不是很简单呢。

    分类:
    后端
    标签: