在 PHP7 中原生分析多个脚本
Natively profile multiple scripts in PHP7
自从 PHP 7 发布后,现在无法在您的基本文件中使用 declare(ticks=1)
分析整个选择的脚本,然后使用 register_tick_function()
监视每个滴答它不再遵循包含路径。根据 PHP 在 https://bugs.php.net/bug.php?id=71448 提交的错误,这将永远不会在 PHP 7.
中再次可用
Due to an implementation bug, the declare(ticks=1) directive leaked into different compilation units prior to PHP 7.0. This is not how declare() directives, which are per-file or per-scope, are supposed to work.
对于这种使用本机 PHP 的方法(不是 C 或 pear 扩展等),我在 PHP 7 中是否有任何替代方法可以让我分析每个函数或文件在页面加载时调用,至少获取实际文件路径的详细信息。
可以在 找到导致发现错误的我最初的问题,现在这个问题是关于替代方法的。
在没有 declare(ticks=1)
的情况下执行此操作的一种常见方法是使用分析器。探查器会注意到 any method/function 调用、文件加载等,甚至会获取时间信息,因此您不仅可以说出哪个函数被调用的时间和调用的代码以及哪个函数文件已打开,但程序的哪一部分花费了多长时间。
PHP 中一个著名的分析器带有著名的 Xdebug 扩展。它还附带一个调试器:
一个好处是您不需要更改代码来进行分析,它只是您需要采用的 PHP 配置,因此您可以根据需要打开和关闭它(例如调试/分析会话)。
PHP Userland(勾选函数)
作为在每个文件的开头(在 #71448 之后)没有 declare(ticks=1);
的变通方法,可以通过file 注入它的协议(对于常见的本地文件系统中的文件)。
这在技术上是可行的,方法是创建一个在文件协议上注册的流包装器来代理标准文件 i/o 操作。在此 PoC (Gist on Github) 中显示了最低限度的实现,以证明它适用于包含。当 test.php
被执行时,尽管 other.php
没有 declare(ticks=1);
在磁盘上,注册的 tick 函数在 include 上被调用,因为回溯的打印显示:
...
tick_handler() called
#0 tick_handler(1) called at [/home/hakre/stream-wrapper-default-files/test.php:18]
#1 tick_handler() called at [/home/hakre/stream-wrapper-default-files/other.php:2]
#2 include(/home/hakre/stream-wrapper-default-files/other.php) called at [/home/hakre/stream-wrapper-default-files/test.php:24]
...
输出是由注册的报价函数生成的(此处:test.php):
<?php
/**
* Inject declare ticks on include
*/
declare(ticks=1);
require __DIR__ . '/streamwrapper.php';
FileStreamWrapper::init();
// using a function as the callback
register_tick_function('tick_handler', true);
// Function which is called on each tick-event
function tick_handler()
{
echo "tick_handler() called\n";
debug_print_backtrace();
}
register_tick_function('tick_handler');
include "other.php";
include "another.php"; # file does not exists
stream wrapper in the gist example 只实现了两个 include 语句所需要的工作量,因为 PHP 脚本通常会做更多的文件 i/o 它需要根据需要进行扩展。当涉及查找等时,需要考虑动态插入等,但每个文件操作(句柄)都有状态,因为每个操作都有一个实例,因此应该很好地封装。全局状态用于 registering/unregistering 每个操作的流包装器代理到真正的文件系统功能,否则它会创建无限递归(包装器使用包装器使用包装器......)。到目前为止的 PoC 展示了它的原理。
这也可以(误)用于其他用途,但此 PoC 适用于您的特定声明标记并包含用例。
自从 PHP 7 发布后,现在无法在您的基本文件中使用 declare(ticks=1)
分析整个选择的脚本,然后使用 register_tick_function()
监视每个滴答它不再遵循包含路径。根据 PHP 在 https://bugs.php.net/bug.php?id=71448 提交的错误,这将永远不会在 PHP 7.
Due to an implementation bug, the declare(ticks=1) directive leaked into different compilation units prior to PHP 7.0. This is not how declare() directives, which are per-file or per-scope, are supposed to work.
对于这种使用本机 PHP 的方法(不是 C 或 pear 扩展等),我在 PHP 7 中是否有任何替代方法可以让我分析每个函数或文件在页面加载时调用,至少获取实际文件路径的详细信息。
可以在
在没有 declare(ticks=1)
的情况下执行此操作的一种常见方法是使用分析器。探查器会注意到 any method/function 调用、文件加载等,甚至会获取时间信息,因此您不仅可以说出哪个函数被调用的时间和调用的代码以及哪个函数文件已打开,但程序的哪一部分花费了多长时间。
PHP 中一个著名的分析器带有著名的 Xdebug 扩展。它还附带一个调试器:
一个好处是您不需要更改代码来进行分析,它只是您需要采用的 PHP 配置,因此您可以根据需要打开和关闭它(例如调试/分析会话)。
PHP Userland(勾选函数)
作为在每个文件的开头(在 #71448 之后)没有 declare(ticks=1);
的变通方法,可以通过file 注入它的协议(对于常见的本地文件系统中的文件)。
这在技术上是可行的,方法是创建一个在文件协议上注册的流包装器来代理标准文件 i/o 操作。在此 PoC (Gist on Github) 中显示了最低限度的实现,以证明它适用于包含。当 test.php
被执行时,尽管 other.php
没有 declare(ticks=1);
在磁盘上,注册的 tick 函数在 include 上被调用,因为回溯的打印显示:
...
tick_handler() called
#0 tick_handler(1) called at [/home/hakre/stream-wrapper-default-files/test.php:18]
#1 tick_handler() called at [/home/hakre/stream-wrapper-default-files/other.php:2]
#2 include(/home/hakre/stream-wrapper-default-files/other.php) called at [/home/hakre/stream-wrapper-default-files/test.php:24]
...
输出是由注册的报价函数生成的(此处:test.php):
<?php
/**
* Inject declare ticks on include
*/
declare(ticks=1);
require __DIR__ . '/streamwrapper.php';
FileStreamWrapper::init();
// using a function as the callback
register_tick_function('tick_handler', true);
// Function which is called on each tick-event
function tick_handler()
{
echo "tick_handler() called\n";
debug_print_backtrace();
}
register_tick_function('tick_handler');
include "other.php";
include "another.php"; # file does not exists
stream wrapper in the gist example 只实现了两个 include 语句所需要的工作量,因为 PHP 脚本通常会做更多的文件 i/o 它需要根据需要进行扩展。当涉及查找等时,需要考虑动态插入等,但每个文件操作(句柄)都有状态,因为每个操作都有一个实例,因此应该很好地封装。全局状态用于 registering/unregistering 每个操作的流包装器代理到真正的文件系统功能,否则它会创建无限递归(包装器使用包装器使用包装器......)。到目前为止的 PoC 展示了它的原理。
这也可以(误)用于其他用途,但此 PoC 适用于您的特定声明标记并包含用例。