Watch Star Fork

JosinWO / phpdoc-parserC

加入码云
与超过 300 万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
PHP注解扩展,便于解析PHP注解信息
Loading...
README.md 13.72 KB

Xan 高性能的PHP扩展AOP框架

An extension for PHP document parsing. written in C code.

Author:Josin 774542602@qq.com | 博客

Xan是一款高性能的易于使用上手的PHP开发框架,颠覆了传统的配置模式,利用注解进行配置,便于优化代码、清晰逻辑;并且基于C语言开发,性能极高。

基于Zend OPCode的AOP特性正在开发中,完全不需要代理的AOP模式,值得拥有!

框架特点:

1、PSR自动加载

2、注解特性

3、AOP编程

4、IOC反转

5、高效视图引擎

6、高效API接口XML与JSON

何为注解?

Java 中到处可见注解的身影,如 @Null or @NotNull 等,其实注解就是一种修饰 变量、类、方法的对象,如下,注解也可以携带参数:

package cn.supjos;

class A
{
    @NotNull(age)
    @Default(age=22, type = "Car")
    @Set("www.supjos.cn", email="774542602@qq.com")
    void test() {

    }
}

PHP 中由于没有语法糖的支持,只能采用注释文档的形式组成注解,如下:

<?php
    
class A
{
    /**
     * @NotNull
     * @Default(age=22, sex="male")
     * @Set("www.supjos.cn", email="774542602@qq.com")
     */
    function test() {

    }
}

特性说明

1、Xan 中,控制器中存在 init() 方法的情况下,引擎会自动从顶级父类开始执行 init() 到本类,不需要用户手动使用 parent::init() 进行调用。

2、 全局变量:Xan\App::$app 表示的是全局的 Xan\App 类的对象;IOC与容器基于此变量。

3、 XML 数据,如果键名为数字也就是索引数组的情况下,系统会自动创建 key 作为元素标签名。系统会自动创建一个 root 键名作为根元素的键名。

AOP切面思想

切面思想:将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低 模块间的耦合度,并有利于未来的可操作性和可维护性;AOP是一个横向的关系组合,也就是将应用中的公共服务进行分离。

重要概念:

1、 连接点 ,程序的一个执行点,Xan 中仅支持方法级别的连接点

2、 切入点 ,捕获连接点的结构,一般可以通过正则匹配或者表达式,目前 Xan 仅支持方法的切入点

3、 通知 ,切入点的业务逻辑代码,目前 Xan 支持(@before, @after, @success, @failure)四种通知

4、 切面 ,定义一个切面类,使用注解: @Aspect 来定义一个切面

5、 引入 ,通过引入附加的属性等,达到修改对象或者类结构的目的,目前 Xan 可以通过注解 AttrAnnotationConstAnnotation 来完成此功能

简单示例:

/**
 * 定义一个切面类
 *
 * @Aspect
 */
class Basic
{
    function before() {        
        echo 'before';
    }
    
    function after($data) {
    	echo 'after =>' . $data;    
    }
    
    function success() {
        echo 'success';
    }
 
    /**
     * 定义通知
     * 通知支持传递参数到指定的切入点,如需指定参数,那么必须使用
     * (value="xxx.xxx", parameters="xxx||xxx||xxx")的格式来指定通知
     * 通知的 value 表示切入点,分别是类名 + "." + 方法名
     * 通知的 parameters 表示参数,多个参数使用 "||"分割
     * 可以完全省略 value 与 parameters 两个参数,直接填入 “类与方法”
     * 如下:
     * 
     * @before("Base.before")
     * @after(value="Base.after", parameters="Xan Extension")
     * @success("Base.success")
     */
    function test() {
        echo 'I\'m the test method for Aspect programming.';
        // 返回true,那么AOP执行 success通知,否则执行 failure 通知
        return true;
    }    
}

// 实例化代理,代理返回的对象可以当做常规对象(new生成的对象一样)使用
$base = Xan\Aop\Proxy::instance(Base::class);

// 调用方法
$base->test();

注意:在Xan中通知是可以无止境的嵌套运行的,也就是一个通知可以嵌套运行另一个通知,每一个通知都有一个通知链,不可以进行闭合通知的,如果闭合通知,则会提示一个 “ Fatal Error:Recursive calling: xx::xx ” 的致命错误

WEB示例

    $loader = new Xan\Loader();
    $loader->setMap('@app', __DIR__);

    $app = new Xan\App();
    $app->bootstrap()->run();

前两行 自动加载功能 , 后两行 框架运行。其中 App构造函数支持全局参数设置。

App构造函数参数

$config = array(
    'urlPattern'        => 'AUTO',         // URL模式:auto、get、path-info
    'defaultModule'     => 'index',        // 默认模块
    'urlGetStr'         => '_xurl',        // GET模式的url键值
    'defaultController' => 'index',        // 默认控制器
    'defaultAction'     => 'index',        // 默认方法
    'viewSuffix'        => 'html',         // 默认视图模板后缀
    'urlSuffix'         => 'html',         // 默认的url后缀,显示指定的情况下,url后缀必传
    'allowModules'      => 'index,home',   // 允许的所有模块,多个模块以逗号分开
    'applicationDir'    => './../apps',    // 应用目录
    'defaultNamespace'  => 'app'           // 应用目录对应的引用空间别名
 );

$app = new Xan\App($config);

控制器

namespace app\modules\index\controllers;

class Index
{

    public function init() {

    }

    /**
     * 默认方法
     */
    public function indexAction() {

    }
}

Xan 中,方法以 Action 结尾,控制器首字母大写,并且不携带后缀: Controller。 如果进行 JSONXML 接口开发,请使用 AOP 注解。

AOP 注解

namespace app\modules\index\controllers;

/**
 * @Aspect
 */
class Index
{

    /**
     * @api(type=JSON,charset=GBK)
     */
    public function indexAction()
    {
        return [
            'Xan' => 'Fast & Easy & Stack.',
            'Version' => 'v0.1.9'
        ];
    }
}

Xan 中,只有框架调用的方法、路由才会解析注解完成 AOP 特性的使用。 Xan 注解分为 类注解方法注解 ,注解类都必须实现 Xan\Type\Annotation\Annotation 接口,接口仅包含有一个方法 input 方法,如下:

namespace app\annotations;

class TagAnnotation implements \Xan\Type\Annotation\Annotation
{
    public function input($objectOrName, $annotations) {
        
    }
}

Xan 解析到一个注解的时候会调用相应的注解类的 input 方法完成注解使用,其中 第一个参数 $objectOrName 在类注解的情况下为 当前的类名称,在方法注解下为当前的类对象。如:

namespace app\moduels\index\controllers;

/**
 * @Aspect
 * @app\annotations\TagAnnotation(version="v1.2.1", aop="Xan")
 */
class Index
{
    /**
     * @LabelAnnotation(v = "V", t = "T")
     */
    public function indexAction() {
        
    }
}


namespace app\annotations;

class TagAnnotation implements \Xan\Type\Annotation\Annotation
{
    public function input($objectOrName, $annotations) {
        
        // $objectOrName
        echo $objectOrName;    // output: app\modules\index\controllers\Index;

        // $annotations:
        print_r($annotations); // output: [ 'version' => 'v1.2.1', 'aop' => 'Xan' ]
    }
}

namespace app\annotations;

class LabelAnnotation implements \Xan\Type\Annotation\Annotation
{
    public function input($objectOrName, $annotations) {
        
        // $objectOrName
        var_dump($objectOrName); // output: new app\modules\index\controllers\Index();

        // $annotations:
        print_r($annotations);   // output: [ 'version' => 'v1.2.1', 'aop' => 'Xan' ]
    }
}

模型

Xan 中模型必须继承于 Xan\Db\Model 抽象类,并且实现方法: tableName()

namesapce app\models;

class User extends \Xan\Db\Model {

    public function tableName() {
        return 'tb_user';
    }

    public function init() {
        // 初始化工作

    }
}

SESSION

XanSESSION 组件包装了系统的 $_SESSION 。 如:

$session = new Xan\Session();

// 设置值
$session->set('hello.xan', 'world');
 <==>
$session['hello.xan'] = 'world';

// 设置的结果就是:
$session = [
    'hello' => [
        'xan' => 'world'
    ]
];

// 获取值
$session->get('hello.xan');
 <==>
$session['hello.xan'];
 <==>
$session['hello']['xan'];

Xan 中SESSION组件可以采用多维数组的方式访问元素内容,但不可以使用多维数组的方式进行修改,因此为了保持一致,推荐采用内置的“.”语言进行设置与访问。

多维的SESSION采用“ . ”进行获取对应的数据。

$_GET|$_POST|$_SERVER

Xan\Request 封装了系统的 $_GET|$_POST|$_SERVER 超全局变量

$_GET

$request = new Xan\Request();

$data = $reqeust->get('data');

// 也可以使用过滤器
$data = $request->get('data', 'strtoupper');
 <==>
$data = $request->get('data', function($data){
    return strtoupper($data);
});

// 也可以指定默认值
$data = $request->get('data', 'strtoupper', 'Xan');

$_POST

$request = new Xan\Request();

$data = $reqeust->getPost('data');

// 也可以使用过滤器
$data = $request->getPost('data', 'strtoupper');

// 也可以指定默认值
$data = $request->getPost('data', 'strtoupper', 'Xan');

$_SERVER

$request = new Xan\Request();

$data = $reqeust->getServer('data');

// 也可以使用过滤器
$data = $request->getServer('data', 'strtoupper');

// 也可以指定默认值
$data = $request->getServer('data', 'strtoupper', 'Xan');

支持环境

>= PHP7.0 Linux/Unix(Mac OS X)

Windows version need to be changed the config.w32 file and compile, wish some one do the job instead of me.

安装

1: CMake 安装

版本 3.10+, 手工修改自带的 CMakeLists.txt 文件的 php 路径即可

cmake .

2: php-configure

/usr/path_to_php/phpize

./configure --with-php-config=/usr/path_to_php/php-config

make -j && sudo make install -j

echo "xannotation.so" >> /usr/path_to_php/php.ini

部分APIs

注解Xan

Xan 类构造函数

final class Xan
{
    function __construct(){};
}

类注解: Xan::getClassDocComment($classNameOrObject)

/**
 * 返回类的注解字符串
 * 
 * @param $classNameOrObject 类名称或者对象
 */
function getClassDocComment($classNameOrObject)
{
    return $this;
}

方法注解:Xan::getMethodDocComment($classNameOrObject, $methodName)

/**
 * 获取方法的注解信息,返回注解字符串
 *
 * @param $classNameOrObject 类名称或者对象
 * @param $methodName        方法名
 */
function getMethodDocComment($classNameOrObject, $methodName)
{
}

解析注解:Xan::parseDocComment($docComments)

/**
 * 返回一个包含注解信息的对象,[body] 包含的是说明信息,其余的注解每一个注解是一个数组
 * 
 * @param $docComments 需要解析的注解信息
 */
function parseDocComment($docComments)
{
}

获取数组形式的注解:Xan::getParseResult($docComments)

/**
 * 同 parseDocComent() 结果,区别在于返回的数组还是对象
 */
function getParseResult($docComments)
{
}

获取类的所有方法的注解信息:parseAllMethodsDocComment($objectOrName)

/**
 * Function: `parseAllMethodsDocComment` used to parsing all methods which in class{$objectOrName}
 * return the object contains the result, the result format like this:
 *
 * The result contains the `num` key means the methods number
 * the `annotations` key contains the result array, each key-value pair contains the key(The function name) & the value(array)
 * each value contains three key-value pairs:
 * `annotations`: The annotations the function contains
 * `num`        : The number of the annotations
 * `body`       : The body of the annotations
 *
 * @param $objectOrName  The class name or object which you want to obtain the annotations
 * @return this          The object contains the value
 */
function parseAllMethodsDocComment($objectOrName) : this
{
}

自动加载 Xan\Loader类

构造函数Xan\Loader::__construct()

namespace Xan;
class Loader
{
    function __construct();
}

设置别名:Xan\Loader::setMap($aliasName, $path)

namespace Xan;
class Loader
{
    function setMap($aliasName, $path);
}

启动自动加载:Xan\Loader::start($prepend = false)

namespace Xan;
class Loader
{
    function autoLoad($prepend = false);
}

类配置工具: Xan\Type\ConfigClass

构造函数 Xan\Type\ConfigClass::__construct()

namespace Xan\Type;
class ConfigClass
{
    function __construct();
}

设置类常量 Xan\Type\ConfigClass::setConstant($className, $key, $value)

namespace Xan\Type;
class ConfigClass
{
    function setConstant($className, $key, $value);
}

设置属性 Xan\Type\ConfigClass::setAttribute($object, $key, $value, $flags = Xan\Type\ConfigClass::PUBLIC)

namespace Xan\Type;
class ConfigClass
{
    function setAttribute($object, $key, $value, $flags = Xan\Type\ConfigClass::PUBLIC);
}

设置属性可见性 Xan\Type\ConfigClass::setAccessFlags($className, $key, $flags = Xan\Type\ConfigClass::PUBLIC)

namespace Xan\Type;
class ConfigClass
{
    function setAccessFlags($className, $key, $flags = Xan\Type\ConfigClass::PUBLIC)
}

项目点评 ( 5 )

你可以在登录后,发表评论

搜索帮助