【问题标题】:How does kint parse PHP functions prefixed by symbols (plus/minus sign, tilde, exclamation mark, at)?kint 如何解析以符号(加号/减号、波浪号、感叹号、at)为前缀的 PHP 函数?
【发布时间】:2017-12-08 13:26:01
【问题描述】:

PHP 调试工具kint 有一种奇怪的语法,其中某些符号可以作为函数的前缀来改变它们的行为,如this guide 所示。

相关信息:

修饰符是一种无需使用其他函数即可更改 Kint 输出的方法。只需在调用 kint 前加上修饰符即可应用它:

! Expand all data in this dump automatically  
+ Disable the depth limit in this dump  
- Attempt to clear any buffered output before this dump  
@ Return the output of this dump instead of echoing it  
~ Use the text renderer for this dump

Example:

+Kint::dump($data); // Disabled depth limit
!d($data); // Expanded automatically

这是如何工作的?

通过查看源代码,这些符号似乎被解析为一个名为$modifiers 的数组。但是你怎么能用 PHP 做到这一点呢?这个范围是什么,我可以用其他 unicode 符号来做吗,还是只有五个有问题的(+、-、~、!、@)。

“@”在 PHP 中已经有了前缀,请参阅:What is the use of the @ symbol in PHP?。这怎么能被推翻?


编辑:对给出的答案的后续问题是 kint 究竟如何弯曲 (php) 规则。例如为什么~ 没有给出语法错误。考虑这个例子:

<?php
function d($args) {
  echo $args[0];
}
d([1,2,3]); // prints 1
~d([1,2,3]); // syntax error, unsupported operand types

<?php
require 'kint.php';
~d([1,2,3]); // prints the array with the text renderer with no issues

编辑 2:删除了 kint 使用 eval() 的未经证实的声明

【问题讨论】:

标签: php kint


【解决方案1】:

抱歉回复晚了。我只是在阅读 Kint 文档并且有同样的问题。找到您的问题后,我决定进行调查。您现在可能已经弄清楚了,但是 kind 实际上会读取调用它的文件的源代码,以根据这些“修饰符”是否存在来改变其行为

就我而言,这种行为是绝对不可预测的,我无法相信任何人会将这种技巧用作概念证明之外的任何东西。值得注意的是,因为文件必须是可读的,kint 修饰符在 eval() 的代码(你不应该开始使用)上失败,也许在其他不寻常的情况下也是如此。

【讨论】:

  • 当从 php 文件执行调用时,kint 可以简单地展开堆栈以查找调用他的内容。如果文件是由 php 执行的,则它可以被 php 读取。对于 99% 的情况,它非常可靠。永远不要使用 eval。我还没有遇到无法以更安全的方式解决的有效 eval 实现。
  • 谢谢,我已经更新了这个问题,并跟进了关于这种滥用 php 是如何完成的,我真的很好奇。
  • “就我而言,这种行为是绝对不可预测的”我很谦虚地迷惑并克服了您对从事激情项目的体面程序员的期望,但这欺骗了您“不敢相信有人会使用“自成立以来的 10 多年中,在各种生产环境中一直是故障安全和万无一失的 :) 另外,请参阅我对这个问题的实际回答 :)
  • @raveren 可以确认,作为用户,我从来没有遇到过任何问题,事实上,我很惊讶它在生产环境中甚至在某些 FS 场景中的运行情况。如果文件在那里,它可以工作!
【解决方案2】:

这里是 Kint 的原作者。

抱歉,您发现它令人困惑!添加了操作数作为简写,用于切换常见用例场景的一些常用设置。

由于 Kint 已经解析了调用它的 PHP 代码以获取并显示正在转储的传递变量的名称(或表达式),因此添加操作数只是对该功能的一个小补充.

注意变量名显示为^。截至撰写本文时,Kint 仍然是唯一可以做到这一点的自卸车!


对OP问题的实际解释来自this in-depth answer

PHP 一元运算符:

因此,完全可以使用这些运算符为函数调用添加前缀,只要函数返回运算符通常会处理的值类型

function foo() {
    return 0;
}

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

【讨论】:

  • 感谢您解决这个问题!我仍然不确定如何。 Alex Howanskys 链接答案中概述的方法是否正确:kint 使用 debug_backtrace() 定位文件,打开并阅读它,然后......到底发生了什么? kint 如何改变我的函数的行为?在我的 OP 示例中,在 d() 前面放置波浪号 ~ 是无效的,因为返回类型 (void) 是“按位非”操作不受支持的操作数类型。但随后它遵循 kint 以某种方式操纵返回值,我认为我的问题的核心是这是如何发生的。
  • 嘿,Kint 只是使用操作数来切换一些内部设置。如果你这样做 $a = ~@d($b);你会在 $a 中得到一个布尔值,因为 @ 强制 kint 返回但 ~ 将返回值转换为 bool。没有办法解决这个问题。
  • 就像我已经提到的那样,操作数是一种快速而愚蠢的方法(如果它有效,它就不是愚蠢的:)方法来切换一些常用的设置。它们在处理组合方面并不是那么健壮,如果您需要更高级/组合的东西,最好只是明确地切换设置。
  • 是的,就像您假设的那样,Kint 使用正则表达式和内置 PHP 标记器的组合方法解析从调试回溯中获得的文件,以获取传递给转储的变量名称或表达式。所以添加操作数功能很容易,我认为这很酷,因为副作用为零当然:)
猜你喜欢
  • 2012-10-20
  • 1970-01-01
  • 2012-12-04
  • 1970-01-01
  • 2012-01-27
  • 2019-07-07
  • 2021-11-02
相关资源
最近更新 更多