今回は楽しい拡張機能を紹介します。 PHP の実行中、つまりデプロイメントの完了後は、定数の値を変更したり、メソッド本体内の実装を変更したりできないことがわかっています。つまり、コーディングが完了したら、そのコードをサーバーにアップロードするのですが、このとき、コードを修正せずに定数の値を変更することはできません。定数自体は変更できません。ただし、runkit 拡張機能は、この機能の実現に役立ちます。
[推奨: PHP ビデオ チュートリアル ]
定数の動的変更
define('A', 'TestA'); runkit_constant_redefine('A', 'NewTestA'); echo A; // NewTestA
すごいと思いませんか?この runkit 拡張機能は、実行時に一部の定数、メソッド本体、クラスを動的に変更できるようにする機能拡張です。もちろん、システム セキュリティの観点から、この拡張機能はあまりお勧めできません。定数の意味は不変の量であるため、変更すべきではありません。同様に、関数本体やクラス定義の内容を実行時に動的に変更すると、それらの関数やクラスを呼び出す他のコードに影響を与える可能性があるため、この拡張機能は危険な拡張機能です。
定数を動的に変更するだけでなく、runkit_constant_add() 関数と runkit_constant_remove() 関数を使用して定数を動的に追加または削除することもできます。
インストール
runkit 拡張機能をインストールするには、github からダウンロードし、通常どおり拡張機能をコンパイルする必要があります。pecl からダウンロードしたものは古いものです。
PHP5: http://github.com/zenovich/runkit
PHP7: https://github.com/runkit7/runkit7.git
成功後のクローン作成通常の拡張機能のコンパイルとインストール手順に従います。
phpize ./configure make make install
PHP バージョンが異なると、異なるバージョンの拡張機能をインストールする必要があります。同時に、runkit7 はまだ開発中であり、次のようないくつかの機能はまだサポートされていません:
- runkit_class_adopt
- runkit_class_emancipate
- runkit_import
- runkit_lint_file
- runkit_lint
- runkit_sandbox_output_handler
- runkit_return_value_used
- Runkit_Sandbox
- Runkit_Sandbox_Parent
この記事のテスト コードを作成したとき、上記の関数またはクラスはサポートされていませんでした。 PHP5環境を使用して、独自の拡張機能が正常に使用できるかテストできます。
スーパー グローバル変数キーの表示
print_r(runkit_superglobals()); //Array //( // [0] => GLOBALS // [1] => _GET // [2] => _POST // [3] => _COOKIE // [4] => _SERVER // [5] => _ENV // [6] => _REQUEST // [7] => _FILES // [8] => _SESSION //)
この関数は、実際に、現在の実行環境内のすべてのスーパー グローバル変数キー名をチェックします。これらは一般的に使用されるスーパーグローバル変数の一部なので、一つずつ説明することはしません。
メソッド関連の操作
メソッドの操作は定数操作と同じで、さまざまなメソッドを動的に追加、変更、削除、名前変更できます。まず、動的ランタイム中にメソッド本体のロジック コードを変更するときに最も懸念される点を見てみましょう。
function testme() { echo "Original Testme Implementation\n"; } testme(); // Original Testme Implementation runkit_function_redefine('testme','','echo "New Testme Implementation\n";'); testme(); // New Testme Implementation
testme() メソッドを定義し、runkit_function_redefine() を通じてその実装を変更します。最後に、testme() が再度呼び出されるとき、出力は新しく変更された実装になります。では、PHP に付属のメソッドを変更できるでしょうか?
// php.ini runkit.internal_override=1 runkit_function_redefine('str_replace', '', 'echo "str_replace changed!\n";'); str_replace(); // str_replace changed! 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 // 3 runkit_function_remove ('array_map'); // array_map(function($v){ // echo $v; // },[1,2,3]); // PHP Fatal error: Uncaught Error: Call to undefined function array_map()
コード内のコメントを見ると非常に明確ですが、php.ini で runkit.internal_override=1 を設定するだけで、PHP に付属のメソッドと関数を動的に変更できます。たとえば、最初の段落では、テキストの段落を直接出力できるように str_replace() メソッドを変更しました。次に、この joinArr() を implode() と同じように使用できるように、implode() の名前を joinArr() に変更します。最後に、array_map() メソッドを削除しましたが、このメソッドを再度呼び出すと、エラーが報告されます。
クラスメソッド関連の操作
クラスの内部メソッド関数の操作は、上記の変数メソッドの操作と似ていますが、PHP に付属のクラスを変更することはできません。これは自分で試すことができます。
//runkit_method_add('PDO', 'testAddPdo', '', 'echo "This is PDO new Func!\n";'); //PDO::testAddPdo(); // PHP Warning: runkit_method_add(): class PDO is not a user-defined class
エラー メッセージから、PDO クラスはユーザー定義クラスではないため、関連する操作に runkit 関数を使用できないことがわかります。次に、カスタム クラスが runkit を使用して動的操作を実行する方法を見てみましょう。
class Example{ } runkit_method_add('Example', 'func1', '', 'echo "This is Func1!\n";'); runkit_method_add('Example', 'func2', function(){ echo "This is Func2!\n"; }); $e = new Example; $e->func1(); // This is Func1! $e->func2(); // This is Func2! runkit_method_redefine('Example', 'func1', function(){ echo "New Func1!\n"; }); $e->func1(); // New Func1! runkit_method_rename('Example', 'func2', 'func22'); $e->func22(); // This is Func2! runkit_method_remove('Example', 'func1'); //$e->func1(); // PHP Fatal error: Uncaught Error: Call to undefined method Example::func1()
空のクラスを定義し、それに 2 つのメソッドを動的に追加し、次にメソッド 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