当前位置: 首页 > 后端技术 > PHP

一起来学习PHP的runkit扩展的使用方法

时间:2023-03-29 21:59:36 PHP

这次给大家带来一个好玩的扩展。我们知道,PHP在运行的时候,也就是部署完成之后,我们不能修改常量的值,也不能修改方法体内部的实现。也就是说,我们完成编码后,将编码上传到服务器。这时候我们不可能不修改代码就去修改一个常量的值。常量本身不允许被修改。不过runkit扩展可以帮我们完成这个功能。动态修改常量define('A','TestA');runkit_constant_redefine('A','NewTestA');回声A;//NewTestA是不是很棒。这个runkit扩展是一个函数扩展,允许我们在运行时动态修改一些常量、方法体和类。当然,从系统安全的角度来说,这个扩展不是很推荐。因为常量的含义本身就是一个不变的量,不应该被修改。同理,在运行时动态改变函数体或类定义的内容可能会影响调用这些函数或类的其他代码,因此这种扩展是一种危??险的扩展。除了动态修改常量,我们还可以使用runkit_constant_add()和runkit_constant_remove()函数来动态添加或删除常量。安装runkit扩展需要到github上下载,然后正常编译。pecl下载已过时。PHP5:http://github.com/zenovich/runkitPHP7:https://github.com/runkit7/runkit7.gitclone成功后,继续正常的扩展编译安装步骤。phpize./configuremakemakeinstall上面PHP不同版本需要安装不同版本的扩展。同时,runkit7还在开发中,部分功能尚不支持,如:runkit_class_adoptrunkit_class_emancipaterunkit_importrunkit_lint_filerunkit_lintrunkit_sandbox_output_handlerrunkit_return_value_usedRunkit_SandboxRunkit_SandboxRunkit_Function代码是本文写测试类时写的或runkit_value_usedRunkit_Sandupbox_Unkit_Sandbox_。可以使用PHP5环境测试原插件是否可以正常使用。查看superglobalskeyprint_r(runkit_superglobals());//数组//(//[0]=>GLOBALS//[1]=>_GET//[2]=>_POST//[3]=>_COOKIE//[4]=>_SERVER//[5]=>_ENV//[6]=>_REQUEST//[7]=>_FILES//[8]=>_SESSION//)这个函数其实就是检查当前运行环境中的所有超全局变量键。这是我们常用的一些超级全局变量,就不一一解释了。方法相关操作方法操作和常量操作一样,我们可以动态的增加、修改、删除和重命名各种方法。首先我们来看看动态运行时我们最关心的修改方法体中逻辑代码的地方。functiontestme(){echo"OriginalTestmeImplementation\n";}testme();//原始Testme实现runkit_function_redefine('testme','','echo"NewTestmeImplementation\n";');testme();//NewTestmeImplementation定义了一个testme()方法,然后使用runkit_function_redefine()修改其实现。最后再次调用testme()时,输出新修改的实现。那么,我们是否可以修改PHP自带的方法呢?//php.inirunkit.internal_override=1runkit_function_redefine('str_replace','','echo"str_replacechanged!\n";');海峡替换();//str_replace改变了!runkit_function_rename('implode','joinArr');var_dump(joinArr(",",['a','b','c']));//string(5)"a,b,c"array_map(function($v){echo$v,PHP_EOL;},[1,2,3]);//1//2//3runkit_function_remove('array_map');//array_map(function($v){//echo$v;//},[1,2,3]);//PHPFatalerror:UncaughtError:Calltoundefinedfunctionarray_map()注释代码中已经很清楚了,我们只需要在php.ini中设置runkit.internal_override=1,就可以动态修改PHP自带的那些方法函数了。比如第一段,我们修改了str_replace()方法,让它直接输出一段文字。然后我们将implode()重命名为joinArr(),我们可以像implode()一样使用这个joinArr()。最后,我们删除了array_map()方法,如果再次调用它会抛出错误。类方法相关的操作类的内部方法函数的操作和上面的变量方法的操作类似,但是我们不能修改PHP自带的类。你可以自己试试这个。//runkit_method_add('PDO','testAddPdo','','echo"ThisisPDOnewFunc!\n";');//PDO::testAddPdo();//PHP警告:runkit_method_add():classPDOisnotauser-definedclass从报错信息可以看出,PDO类不是用户自定义类,所以无法使用runkit函数进行相关操作。那我们来看看我们的自定义类是如何使用runkit进行动态操作的。classExample{}runkit_method_add('Example','func1','','echo"ThisisFunc1!\n";');runkit_method_add('Example','func2',function(){echo"这是Func2!\n";});$e=新例子;$e->func1();//这是Func1!$e->func2();//这是Func2!runkit_method_redefine('Example','func1',function(){echo"NewFunc1!\n";});$e->func1();//NewFunc1!runkit_method_rename('Example','func2','func22');$e->func22();//ThisisFunc2!runkit_method_remove('Example','func1');//$e->func1();//PHPFatalerror:UncaughtError:CalltoundefinedmethodExample::func1()我们定义了一个空的类,然后给它动态添加两个方法,然后修改方法1,重命名方法2,最后删除方法1。一系列操作和上面的普通方法基本一样。的。总结正如上面所说,这个扩展是一个危险的扩展,尤其是启用runkit.internal_override的情况下,我们还可以修改PHP的原生函数。但如果你必须使用它,那么它的功能就非常有用。就像访问者模式一样,“大多数时候你不需要访问者模式,但是当你需要访问者模式的时候,你真的需要它”,这套runkit扩展也是如此。测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202006/source/%E4%B8%80%E8%B5%B7%E5%AD%A6%E4%B9%A0PHP%E7%9A%84runkit%E6%89%A9%E5%B1%95%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8.php参考文档:https://www.php.net/manual/zh/book.runkit.phphttps://www.php.net/manual/zh/book.runkit7.php各媒体平台均可搜索【硬核项目经理】