이번에는 재미있는 확장 기능을 가져왔습니다. 우리는 PHP가 실행 중일 때, 즉 배포가 완료된 후에는 상수 값을 수정할 수 없으며 메서드 본문 내부의 구현을 수정할 수도 없다는 것을 알고 있습니다. 즉, 코딩을 마친 후 코드를 서버에 업로드하게 되는데, 이때 코드를 수정하지 않고는 상수값을 수정할 수 없습니다. 상수 자체는 수정할 수 없습니다. 그러나 Runkit 확장은 이 기능을 수행하는 데 도움이 될 수 있습니다.
【추천: PHP 비디오 튜토리얼】
상수의 동적 수정
define('A', 'TestA'); runkit_constant_redefine('A', 'NewTestA'); echo A; // NewTestA
멋지지 않나요? 이 런킷 확장은 런타임 시 일부 상수, 메서드 본문 및 클래스를 동적으로 수정할 수 있게 해주는 기능적 확장입니다. 물론 시스템 보안 관점에서 볼 때 이 확장은 그다지 권장되지 않습니다. 상수의 의미는 변하지 않는 수량이므로 수정해서는 안 됩니다. 마찬가지로, 런타임 시 함수 본문이나 클래스 정의의 내용을 동적으로 변경하면 이러한 함수나 클래스를 호출하는 다른 코드에 영향을 미칠 수 있습니다. 따라서 이 확장은 위험한 확장입니다.
동적으로 상수를 수정하는 것 외에도 runkit_constant_add() 및 runkit_constant_remove() 함수를 사용하여 상수를 동적으로 추가하거나 삭제할 수도 있습니다.
설치
runkit 확장을 설치하려면 github에서 다운로드한 다음 확장을 정상적으로 컴파일해야 합니다. pecl 다운로드가 오래되었습니다.
PHP5: http://github.com/zenovich/runkit
PHP7: https://github.com/runkit7/runkit7.git
Clone 성공 후 일반 확장 컴파일 및 설치 단계를 따르세요.
phpize ./configure make make install
서로 다른 PHP 버전은 서로 다른 확장 버전을 설치해야 합니다. 동시에 runkit7은 아직 개발 중이며 다음과 같은 일부 기능은 아직 지원되지 않습니다.
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와 함께 제공되는 메서드와 함수를 동적으로 수정하려면 php.ini에서 runkit.internal_override=1만 설정하면 됩니다. 예를 들어 첫 번째 문단에서는 텍스트 문단을 직접 출력할 수 있도록 str_replace() 메서드를 수정했습니다. 그런 다음 implode()와 마찬가지로 이 JoinArr()을 사용할 수 있도록 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()
빈 클래스를 정의한 다음 여기에 두 개의 메서드를 동적으로 추가한 다음 메서드 1을 수정하고 메서드 2의 이름을 바꾸고 마지막으로 메서드 1을 삭제했습니다. 일련의 작업은 실제로 위의 일반 메서드와 동일합니다.
요약
위에서 언급했듯이 이 확장은 상대적으로 위험한 확장입니다. 특히 runkit.internal_override가 켜져 있는 경우 PHP의 기본 기능을 수정할 수도 있습니다. 하지만 꼭 사용해야 한다면 그 기능은 매우 유용합니다. 방문자 패턴과 마찬가지로 "대부분의 경우 방문자 패턴이 필요하지 않지만 방문자 패턴이 필요할 때는 실제로 필요합니다." 이 런킷 확장 세트에도 마찬가지입니다.
테스트 코드:
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