扩展 PHP Class 以允许通过 __callStatic 找到的新方法

Extend PHP Class to allow new methods found via __callStatic

寻找一种灵活的方式来允许其他开发人员为模板系统扩展渲染方法,基本上允许他们生成自己的 render::whatever([ 'params' ]) 方法。

从单个开发人员的角度来看,当前的设置工作得很好,我有许多基于上下文(post、媒体、分类法等)的 classes 设置,其中__callStatic 方法收集调用函数,检查 method_exists 是否在 class 中,如果是,则提取任何传递的参数并呈现输出。

快速示例(伪代码):

-- view/page.php

render::title('<div>{{ title }}</div>');

-- app/render.php

class render {

    public static function __callStatic( $function, $args ) {
         
        // check if method exists 
        if ( method_exists( __CLASS__, $function ){

            self::{ $function }( $args );

        }

    }

    public static function title( $args ) {
         
        // do something with the passed args...

    }

}

我想允许开发人员从他们自己包含的 class 中扩展可用的方法 - 这样他们就可以创建例如 render::date( $args ); 并将其传递给他们的逻辑以收集数据,然后再呈现结果到模板。

问题是,哪种方法最有效且性能最好 - 错误和安全性在这一点上不是一个大问题,可以稍后再解决。

编辑 --

我已经通过执行以下操作(再次伪代码..)来完成这项工作:

-- app/render.php

class render {

    public static function __callStatic( $function, $args ) {
         
        // check if method exists 
        if ( 
            method_exists( __CLASS__, $function
        ){

            self::{ $function }( $args );

        }

        // check if method exists in extended class
        if ( 
            method_exists( __CLASS__.'_extend', $function 
        ){

            __CLASS__.'_extend'::{ $function }( $args );

        }

    }

    public static function title( $args ) {
         
        // do something with the passed args...

    }

}

-- child_app/render_extend.php

class render_extend {

    public static function date( $args = null ) {

        // do some dating..

    }

}

这里的问题是这仅限于基础 render() 的一个扩展 class。

一种常见的方式(由 Twig 和 Smarty 使用,举几个例子)是要求开发人员手动将他们的扩展注册为可调用对象。 render class 保留了它们的记录,然后除了检查自己的内部方法外,还检查来自 _callStatic.

的列表

根据您已有的资料,这可能看起来像这样:

class render
{
    /** @var array */
    private static $extensions;
    
    public static function __callStatic($function, $args)
    {
        // check if method exists in class methods...
        if ( method_exists( __CLASS__, $function )) {
            self::{$function}(self::$args);
        }
        // and also in registry
        elseif (isset(self::$extensions[$function])) {
            (self::$extensions[$function])($args);
        }
    }
    
    public static function title($args)
    {
        // do something with the passed args...
    }
    
    public static function register(string $name, callable $callback)
    {
        self::$extensions[$name] = $callback;
    }
}

开发人员会像这样使用它:

render::register('date', function($args) {
    // Do something to do with dates
});

完整演示在这里:https://3v4l.org/oOiN6