PHP : 클래스 메소드의 입력/출구시 콜백?
-
08-07-2019 - |
문제
각 메소드 내에서 명시 적 호출을하지 않고 메소드 매개 변수, 항목 및 출구에서 콜백을 설정할 수있는 방법이 있습니까? 기본적 으로이 정보를 각 방법에 대해 수동으로 수행하지 않고도 로거 클래스 (정적)에 로그인하고 싶습니다.
지금 당장 나는 이것을 달성하기 위해 모든 방법에서 logger :: logentry () 및 logger :: logexit ()를 호출해야합니다. 나는 이것을 할 필요가 없다 :
class TestClass {
public function tester($arg) {
Logger::logEntry();
Logger::info('Parameter $arg => ' . $arg);
// Do some stuff...
Logger::logExit();
}
}
해결책
래퍼 클래스를 사용하십시오. 이 방법에는 다음과 같은 이점이 있습니다.
- 기본 클래스 구조 / 방법 서명을 변경할 필요가 없습니다.
- 로깅 변경? 이 클래스를 업데이트하십시오
- 객체 호출 업데이트 대 로그하려는 모든 클래스에 코드 삽입
.
class LogWatch {
function __construct($class) {
$this->obj = $class;
}
function __call($method, $args) {
if (in_array($method, get_class_methods($this->obj) ) ) {
Logger::logEntry();
Logger::info('Parameter '.implode(', ', $args) );
call_user_func_array(array($this->obj, $method), $args);
Logger::logExit();
} else {
throw new BadMethodCallException();
}
}
}
$test = new LogWatch(new TestClass() );
$test->tester();
// you can use instances of `LogWatch()` just like your watched class
// including passing appropriate params:
$test->tester($param1, $param2);
다른 팁
디버깅을 위해 기능 로깅을하고 싶다면 Xdebug 확장자를 살펴볼 수 있습니다. 런타임에서 기능 호출을 가로 채는 좋은 방법은 없으며 자동화 된 가로 채기는 훌륭한 런타임 오버 헤드를 추가합니다.
xdebug를 사용하면 대신 필요로하는 것만으로도 다른 것들을 얻을 수 있습니다.
(따라서 XDEBUG는 PHPUNIT와 함께 사용하여 단위 테스트 및 범위 분석을 수행합니다.)
__call의 문제
__call은 문제에 대한 재미있는 해결책이 될 수 있지만 3 이 문제, 즉 문제
상당한 실행 오버 헤드. __call-> call_user_func_array를하고 있습니다. 말 그대로 하나를 추가하지는 않지만 둘 모든 실행에 대한 기능 호출.
배경 트레이스가 구분할 수 없게됩니다. 전화하려고했던 실제 기능은 __call 및 call_user_func_array의 바다에서 길을 잃어 버립니다.
멍청한 숨겨진 기능 : _로 직접 호출하거나 보는 것을 막기 위해 _로 접두사의 "숨기기"로 돌아갑니다. 함수 이름의 이름을 want이면 __call로 돌아갑니다. 트리거는 원하지 않으므로 이미 끔찍한 기능 이름으로 가득 찬 전체 수업을 받았습니다. 개발자들은 다양한 장소에서 직접 전화를 받고 싶어합니다. (그리고 나중에 __call을 제거하려면 코드를 깨지 않도록 이러한 모든 기능을 바꿔야합니다!)
따라서 PHP 코드를 사용하여이를 구현하는 경우, Codebase의 미래의 사용자는 아니다 함께 일하고 싶습니다. 필요할 때 투명하게 추가 할 수있는 Xdebug와 같은 무언가를 얻는 것이 훨씬 더 좋습니다.
마법 기능을 사용할 수 있습니다 __call
. 기능이 해당 이름과 일치 할 때 호출됩니다. 방법의 이름을 바꾸어 무언가 (예 : 밑줄)로 접두사를 달성하고 선택적으로 개인/보호로 설정하십시오.
class TestClass {
public function __call($function, $args) {
Logger::logEntry();
Logger::info('Parameters: ' . implode(", ", $args);
$localFunc = "_" . $function;
$return = $this->$localFunc($args);
Logger::logExit();
return $return;
}
private function _tester() {
// do stuff...
return "tester called";
}
}
$t = new TestClass();
echo $t->tester();
// "tester called"