此包已废弃,不再维护。未建议替代包。

JSON Docblock 注释解析器

维护者

详细信息

git.sr.ht/~shabbyrobe/nope

1.0.3 2015-08-04 12:10 UTC

This package is not auto-updated.

Last update: 2024-09-07 09:56:21 UTC


README

注意:由于 PHP 8 添加了对属性的原生支持,这已被废弃。它将不再收到更新。

Nope!- PHP 的 JSON Docblock 注释解析器

在 docblocs 中以 JSON 格式指定注释。

需要 PHP 5.4 或更高版本。使用 `composer` 安装

composer require shabbyrobe/nope

此示例演示了 Nope 几乎提供的一切

<?php
require 'vendor/autoload.php';

/**
 * Hellos your hellos
 *
 * :c1 = {
 *     "foo": true,
 *     "bar": ["baz", "qux"],
 *     "ding": {"dong": "woohoo"}
 * };
 * :c2 = {"foo": false};
 *
 * @author Mr. Pants
 */
class Hello
{
    /** :p1 = {"pants": true}; */
    public $pants;

    /** :m1 = {"foo": true}; */
    function world($foo, $bar)
    {
        return "Hello, World!";
    }
}

$parser = new Nope\Parser();
$t = microtime(true);
$out = $parser->parseClass('Hello');

var_dump($out);
var_dump(microtime(true) - $t);

结果:

stdClass#1 (
    [notes] => array (
        'c1' => array (
            'foo' => true
            'bar' => array ( '0' => 'baz' '1' => 'qux' )
            'ding' => array ( 'dong' => 'woohoo' )
        )
        'c2' => array ( 'foo' => false )
    )
    [methods] => array (
        'world' => array(
            'm1' => array ( 'foo' => true )
        )
    )
    [properties] => array (
        'pants' => array (
            'p1' => array ( 'pants' => true )
        )
    )
)
float(0.00057697296142578)

它足够快,但你仍然可能想在生产服务器上缓存该结果。

Nope 注释遵循简单格式

/**
 * :namespace = JSON;
 */

解析规则简单明了

  • Docblock 边距被移除。

  • 解析器查找以冒号 (`:`) 开头的任何行并开始解析。

  • 从冒号到等号 (`=`) 之间的所有内容(不包括尾随空格)被视为 命名空间

  • 等号 (`=`) 之后的所有内容(不包括前导空格)**必须为有效 JSON**。解析结束时,如果遇到行尾的 `; 作为 最后一个 字符,则解析结束。

  • 会解析多个注释,但如果您指定了相同的命名空间两次,则第二个定义将 覆盖 第一个。

docblock 内部的其他所有内容都被忽略,因此这不应干扰您的文档。

如果您需要在 docblock 中的某一行以 `: 开头,请使用 转义符 转义: \:

由于 JSON 字符串不能跨多行,因此 `;\n` 字符串不可能出现在有效 JSON 的任何地方。这是我们利用的特性,使得 Nope 成为可能。因此,以下示例不能被 Nope 成功解析

<?php
/** :foo = true; :bar = true; */
function impossible() {}

请务必小心在您的库和应用程序中添加新的命名空间。理想情况下,您应该为整个应用程序定义一个命名空间,并将您的注释作为对象嵌入其中。这解决了“每行一个注释”的问题

<?php
/** :myapp = {"foo": "bar", "baz": "qux"}; */
function good() {}

/**
 * :foo = "bar";
 * :baz = "qux";
 */
function please_dont() {}

API

解析类、特质或接口中的所有注释

<?php
/** :foo = {"yep": true}; */
class Pants
{
    /** :foo = {"yep": true}; */
    public $property;

    /** :foo = {"yep": true}; */
    public function test() {}
}

$result = $parser->parseClass('Pants');
$result = $parser->parseClass(new \ReflectionClass('Pants'));

这会产生以下结果:

stdClass#1 (
    [notes] => array (
        'foo' => array (
            'yep' => true
        )
    )
    [properties] => array (
        'property' => array (
            'foo' => array (
                'yep' => true
            )
        )
    )
    [methods] => array (
        'test' => array (
            'foo' => array (
                'yep' => true
            )
        )
    )
)

解析文档注释中的所有注释

<?php
/** :foo = {"bar": true}; */
function func()
{}

$function = new ReflectionFunction('func');
$notes = $parser->parseDocComment($function->getDocComment());
$parsesTo = array(
    'foo'=>['bar'=>true],
);

解析字符串中的所有注释

<?php
$string = ':foo = {"bar": true};';
$notes = $parser->parse($string);
$parsesTo = array(
    'foo'=>["bar"=>true],
);

解析反射器数组中的所有注释(必须支持 `name` 属性和 getDocComment()` 方法

<?php
$rc = new ReflectionClass('Pants');
$notes = $parser->parseReflectors($rc->getMethods(ReflectionMethod::IS_STATIC));

可以将方法过滤器和属性过滤器传递给 `parseClass`

<?php
$rc = new ReflectionClass('Pants');
$notes = $parser->parseClass(
    \Pants::class, 
    \ReflectionProperty::IS_PUBLIC,
    \ReflectionMethod::IS_STATIC
);

这不是一个已经解决的问题吗?

Nope!(实际上自从 PHP 8 以来是 “yep”)

多年来我尝试了大约六次解决这个问题,但我对现有的解决方案并不满意。我喜欢基于属性的元编程,并认为它应该被原生支持,但看起来这不会很快出现在 PHP 中。

实际上已经有很多这样的工具了,其中一些是我自己推向世界的(抱歉)。

一个常见的做法是定义一种复杂的新语言。这些语言通常与纯 PHP 略有不同,这每次您在它们之间切换使用时都会带来认知负荷。您也倾向于比写其他代码更少地编写注释,因此您会在手册中查找很多时间来填补空白。

它们甚至还需要基于PHP的复杂实现来慢速解析器才能被阅读。我长期以来一直对这些解决方案感到不舒服——它们速度太慢,部件太多。

在我的数据映射器项目 Amiss <http://github.com/shabbyrobe/amiss> 中,我曾尝试过两次创建一个更轻量级的替代方案,但都失败了(参见v3和v4),原因在于它们太不熟悉且/或不够灵活。

我一直坚信,在PHP的标准库中隐藏着一个基于原生C的解决方案,这已经有一段时间了,我很震惊我竟然花了这么长时间才意识到 `json_decode` 整个时间都在我眼前。

这完全符合工作需求:它可以表示与纯PHP映射良好的复杂数据结构,语言无处不在且广为人知,PHP中有一个快速C解析器,可以在一个函数调用中提供。

不是这样的 利用这些特性,通过在文档注释中找到一种方法,将JSON无歧义地嵌入到非结构化文本字符串中。