如何在函数调用之前注入和删除 php 代码

发布于 2025-01-05 05:17:24 字数 120 浏览 0 评论 0 原文

我希望能够在特定函数之前和之后注入一些 php 代码(分析器代码)。 函数和文件将手动插入到表单中,但我希望注入和删除是自动的。我使用正则表达式来定位所需的函数调用,但我找不到如何在其之前放置启用代码并在其之后放置禁用代码。

I want to be able to inject some php code (a profiler code) before and after a specific function.
The function and the file will be inserted manually in a form, but I want the injection and the removal to be automatically. I use a regular expression to locate the desired function call but I couldn't not find how to place the enabling code before and the disabling code after it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

演多会厌 2025-01-12 05:17:24

我希望能够在特定函数之前和之后注入一些 php 代码(分析器代码)。函数和文件将手动插入到表单中,但我希望注入和删除是自动的。我使用正则表达式来定位所需的函数调用,但我找不到如何在其之前放置启用代码并在其之后放置禁用代码。

我想,错误的问题会产生错误的答案。如果您想分析特定函数,请使用 XDebug 之类的分析器,而不是您自己编写的分析器。执行分析的代码注入听起来是一项艰巨的工作,尽管可以使用 runkit,如 Vyktor 建议的那样。

如果您确实想运行自己的代码,我想最简单的解决方案是执行以下操作:

<?php
$profiler = function( $function ) {
   // your profiling code here.
};

$profiler( 'yourfunction' );
yourfunction( );
$profiler( 'yourfunction' );

然后,当您完成对应用程序的分析后,您可以简单地使用 $profiler 不执行任何操作,这意味着它不会具有侵入性。

$profiler = function( $function ) {
    return;
};

尽管如此,这仍然会使分析遍布整个应用程序。我只是使用现有的工具。

I want to be able to inject some php code (a profiler code) before and after a specific function. The function and the file will be inserted manually in a form, but I want the injection and the removal to be automatically. I use a regular expression to locate the desired function call but I couldn't not find how to place the enabling code before and the disabling code after it.

The wrong question will yield the wrong answers, I guess. If you want to profile specific functions, use a profiler like XDebug instead of a profiler you write yourself. Code injection to perform profiling sounds like a terrible amount of work, although it is possible using runkit, as Vyktor suggested.

If you actually want to run your own code, I guess the easiest solution would be to do something like this:

<?php
$profiler = function( $function ) {
   // your profiling code here.
};

$profiler( 'yourfunction' );
yourfunction( );
$profiler( 'yourfunction' );

Then, when you're done with profiling the application, you can simply use an alternative function for $profiler that does nothing, which means it won't be intrusive.

$profiler = function( $function ) {
    return;
};

Still, this leaves profiling spread all over your application. I'd just use the existing tools.

心碎无痕… 2025-01-12 05:17:24

函数 - runkit

您可以使用 php runkit 来简单地重写该函数。假设您想要替换函数 foo(),首先您需要使用 runkit_function_rename()

runkit_function_rename( 'foo', '_foo');

不仅仅是简单地重新定义函数(通过 func_get_args()call_user_func_array()):

function foo() {
  // Pre code
  $result = call_user_func_array( '_foo', func_get_args());
  // Post code
  return $result;
}

一旦你重新完成后,您可以删除临时函数runkit_function_remove()

runkit_function_remove( 'foo');

// And set up old one back
runkit_function_rename( '_foo', 'foo');

如果您确实需要更改函数的代码(内联)并且“预回调”和“后回调”还不够,那么恐怕我有关于您的应用程序设计的坏消息。

方法 - 简单包装

当您需要更新方法(而不是函数)时,您可以利用 php 神奇方法,您可能应该实现所有这些方法,但我将仅展示__call(), __set(), __get()__isset()

class Wrapper {
// The class that we are about to handle
protected $___data = null;

// Actually the only function that is directly related  to Wrapper class
public function __construct( $data){
    $this->___data = $data;
}

// By default just call real method
// You may add pre and post callbacks for every function
public function __call( $funcName, $args){
    return call_user_func_array( array( $this->___data, $funcName), $args);
}

// Propagate set to deeper level
public function __set( $key, $val){
    $result = ($this->___data->{$key} = $val);
    if( $result == $this->___data){
        return $this;
    }
    return $result;
}

// Propagate get to deeper level
public function __get( $key){
    $result = $this->___data->{$key};
    if( $result == $this->___data){
        return $this;
    }
    return $result;
}

// Handles isset
public function __isset( $key){
    return isset( $this->___data->{$key});
}

}

一旦你有了这个,你可以简单地扩展这个类,只是为了对一个方法进行特殊处理(比如类 Bar 方法 foo()):

WrapperBar extends Wrapper {
    public function foo(){
         // Add magick
         return call_user_func_array( array( $this->___data, 'foo'), func_get_args());
    }
}

并将其用作:

 $bar = new Bar();
 $bar = new WrapperBar( $bar);
 $bar->foo( 'One', 'Two', '...');

Functions - runkit

You may use php runkit to simply rewrite that function. Let's say you want replace function foo(), at first you need to rename that function with runkit_function_rename():

runkit_function_rename( 'foo', '_foo');

And than just simply redefine your function (with dynamic handling of arguments via func_get_args() and call_user_func_array()):

function foo() {
  // Pre code
  $result = call_user_func_array( '_foo', func_get_args());
  // Post code
  return $result;
}

Once you're done, you may remove temporary function runkit_function_remove():

runkit_function_remove( 'foo');

// And set up old one back
runkit_function_rename( '_foo', 'foo');

If you really need to change code of your function (inline) and "pre callback" and "post callback" aren't enough I'm afraid I've got bad news about your application design.

Methods - simple wrapper

When you need to update methods (not functions) you can encapsulate whole object with simple wrapper taking advantage of php magic methods, you should probably implement all of them, but I'm going to show just __call(), __set(), __get() and __isset().

class Wrapper {
// The class that we are about to handle
protected $___data = null;

// Actually the only function that is directly related  to Wrapper class
public function __construct( $data){
    $this->___data = $data;
}

// By default just call real method
// You may add pre and post callbacks for every function
public function __call( $funcName, $args){
    return call_user_func_array( array( $this->___data, $funcName), $args);
}

// Propagate set to deeper level
public function __set( $key, $val){
    $result = ($this->___data->{$key} = $val);
    if( $result == $this->___data){
        return $this;
    }
    return $result;
}

// Propagate get to deeper level
public function __get( $key){
    $result = $this->___data->{$key};
    if( $result == $this->___data){
        return $this;
    }
    return $result;
}

// Handles isset
public function __isset( $key){
    return isset( $this->___data->{$key});
}

}

Once you have this, you may simply extend this class just to have special handling for one method (say class Bar method foo()):

WrapperBar extends Wrapper {
    public function foo(){
         // Add magick
         return call_user_func_array( array( $this->___data, 'foo'), func_get_args());
    }
}

And use it as:

 $bar = new Bar();
 $bar = new WrapperBar( $bar);
 $bar->foo( 'One', 'Two', '...');
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文