shabbyrobe / nope
JSON Docblock 注释解析器
Requires
- php: >=5.4.0
- seld/jsonlint: *
Requires (Dev)
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无歧义地嵌入到非结构化文本字符串中。