php - 如何从 Kint 模拟/捕获不寻常的 PHP 操作数

标签 php operands kint

背景(简介)
Kint是一个 PHP 调试工具,可以作为 PHP 的 var_dump()print_r()debug_backtrace() 的更强大的替代品。 Kint 的一项不寻常功能(至少对于 PHP 而言)是能够以操作数的形式使用实时修饰符。以下是手册中有关该功能的说明:

There are a couple of real-time modifiers you can use:

  • ~d($var) this call will output in plain text format.
  • +d($var) will disregard depth level limits and output everything. Careful, this can hang your browser on large objects!
  • !d($var) will expand the output automatically.
  • -d($var) will attempt to ob_clean the previous output and flush after printing.
  • You can combine modifiers too: ~+d($var)

有一个older exiting SO question如果您需要更多信息,这与此问题类似。


问题

  1. Kint 如何添加这些操作数而不触发 PHP 错误?
  2. 如何模拟/捕获使用这些操作数的任何调用?

如果您尝试使用这些操作数或创建自己的函数来捕获 Kint 操作数调用,则在不加载 Kint 的情况下,您会收到 fatal error :未捕获错误:不支持的操作数类型

重要提示:我正在使用 kint.phar 文件,并且没有使用 Composer 或任何类型的 CLI 用法。



我的用例(请不要从问题中分心)
我为那些好奇的人添加此信息并进一步澄清我的问题。我真诚地想了解和了解他们是如何做到这一点的,并希望得到答案。这个问题不是关于捍卫/批评/不同意我的用例:

为了安全和优化,我正在创建一个假(空)Kint 类,该类在我的网站处于生产模式时加载。这确保了代码中意外留下的任何 Kint 调用都不会触发 fatal error ,永远无法打印出任何内容,并且与加载真实的 Kint 类相比使用更少的资源。

我知道您可以使用 Kint::$enabled_mode = false; 禁用 Kint,但我们不要关注这一点。这是我用来伪造 Kint 类的代码。所缺少的只是捕获使用这些非标准操作数的调用:

/**
 * Fake class.
 */
class Kint {

    const STATIC_BLACKHOLE = '';

    public static $enabled_mode = false;

    public function blackhole( $a ) {
        return;
    }

    public function __call( $m, $a ) {
        return call_user_func_array( array( $this, $this->blackhole ), $a );
    }

    public static function __callStatic( $m, $a ) {
        return self::STATIC_BLACKHOLE;
    }

}
$kint = new Kint();

// Alias of Kint::dump().

/**
 * Fake function to catch d().
 *
 * @return void
 */
function d() {
    return;
}

// Kint::dump basic mode.

/**
 * Fake function to catch s().
 *
 * @return void
 */
function s() {
    return;
}

\define( 'KINT_DIR', '/classes/Kint' );
\define( 'KINT_WIN', DIRECTORY_SEPARATOR !== '/' );
\define( 'KINT_PHP70', ( \version_compare( PHP_VERSION, '7.0' ) >= 0 ) );
\define( 'KINT_PHP71', ( \version_compare( PHP_VERSION, '7.1' ) >= 0 ) );
\define( 'KINT_PHP72', ( \version_compare( PHP_VERSION, '7.2' ) >= 0 ) );
\define( 'KINT_PHP73', ( \version_compare( PHP_VERSION, '7.3' ) >= 0 ) );
\define( 'KINT_PHP74', ( \version_compare( PHP_VERSION, '7.4' ) >= 0 ) );
\define( 'KINT_PHP80', ( \version_compare( PHP_VERSION, '8.0' ) >= 0 ) );

最佳答案

“实时修饰符”都是有效的 PHP 一元运算符:

因此,完全可以在函数调用前加上这些运算符,只要函数返回运算符通常处理的值的类型:

function foo() {
    return 0;
}

// All of these work just fine, and generate no errors:
-foo();
+foo();
!foo();
~foo();

据我一眼就能看出,Kint 在其函数内部所做的是使用 debug_backtrace() 来获取调用该函数的源文件。然后,它打开该文件,读取它,找到调用行,并解析它以确定使用什么(如果有)“实时修饰符”作为函数调用的前缀。即,考虑来源:

function d($var) {
    // dump $var
}

~d($GLOBALS);

d() 函数内部的代码通常无法判断其返回值将被 ~ 运算符修改。 (它不应该!这样做完全违反了词法和逻辑范围。)但是,Kint 逃脱了这个范围,重新解析源文件,找到 ~,然后使用它作为一种手段修改函数内部代码生成的输出。

这种技术非常令人困惑,造成了巨大的性能损失,违反了范围界定,并提出了安全问题......所有这些都是为了提供该语言已经具有的基本功能(函数参数)的较差实现。我永远不会让这个模块靠近我的任何生产服务器。

也就是说,我的建议是忘记尝试用 noops 覆盖 Kint 的运行时功能。相反,构建管道以使 Kint 无法部署:

  • 确保在您的 compose require 中使用 --dev
  • 确保在部署脚本中使用 --no-dev
  • 向 Bootstrap 或前端 Controller 添加一个检查,以便在加载 Kint 时立即中止。
  • 在部署之前使用 PHPCS 中的“禁止函数”嗅探,以检测源代码中遗留的 Kint 函数的任何使用情况。

关于php - 如何从 Kint 模拟/捕获不寻常的 PHP 操作数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69845019/

相关文章:

php - 拉维尔 5.3 : Passport Implementation - {"error" :"invalid_client" ,"message" :"Client authentication failed"}

Java计算器(运算顺序)

linux - 在两个日期变量之间插入文本

php - 任何生成图形和饼图的好类

php - 发送消息回调后的jaxl

php - WordPress:按月对帖子进行分组?

swift - 二元运算符 > 错误

php - kint 如何解析以符号(加号/减号、波浪号、感叹号、at)为前缀的 PHP 函数?

php - Composer : Specify autoload_files require order