새로운 메서드를 php 오브젝트에 즉시 추가하는 방법은?
오브젝트에 새로운 메서드를 추가하려면 어떻게 해야 합니까?
$me= new stdClass;
$me->doSomething=function ()
{
echo 'I\'ve done something';
};
$me->doSomething();
//Fatal error: Call to undefined method stdClass::doSomething()
이를 위해 사용할 수 있습니다.
class Foo
{
public function __call($method, $args)
{
if (isset($this->$method)) {
$func = $this->$method;
return call_user_func_array($func, $args);
}
}
}
$foo = new Foo();
$foo->bar = function () { echo "Hello, this function is added at runtime"; };
$foo->bar();
에서는 익명할 수 .stdClass
★★★★★★ 。
$myObject = new class {
public function myFunction(){}
};
$myObject->myFunction();
런타임에 새로운 메서드를 추가할 수 있도록 단순히 __call을 사용하는 것은 이러한 메서드가 $this 인스턴스 참조를 사용할 수 없다는 큰 단점이 있습니다.추가된 메서드가 코드에 $this를 사용하지 않을 때까지 모든 것이 잘 작동합니다.
class AnObj extends stdClass
{
public function __call($closure, $args)
{
return call_user_func_array($this->{$closure}, $args);
}
}
$a=new AnObj();
$a->color = "red";
$a->sayhello = function(){ echo "hello!";};
$a->printmycolor = function(){ echo $this->color;};
$a->sayhello();//output: "hello!"
$a->printmycolor();//ERROR: Undefined variable $this
이 문제를 해결하기 위해 패턴을 다음과 같이 다시 쓸 수 있습니다.
class AnObj extends stdClass
{
public function __call($closure, $args)
{
return call_user_func_array($this->{$closure}->bindTo($this),$args);
}
public function __toString()
{
return call_user_func($this->{"__toString"}->bindTo($this));
}
}
이 방법으로 인스턴스 참조를 사용할 수 있는 새로운 메서드를 추가할 수 있습니다.
$a=new AnObj();
$a->color="red";
$a->sayhello = function(){ echo "hello!";};
$a->printmycolor = function(){ echo $this->color;};
$a->sayhello();//output: "hello!"
$a->printmycolor();//output: "red"
업데이트: 여기에 표시된 접근 방식에는 다음과 같은 주요 단점이 있습니다.새로운 함수는 클래스의 완전 수식 멤버가 아닙니다.
$this
이 방법으로 호출되면 메서드에 존재하지 않습니다., 인스턴스의 .이 URL에는 할 수 .private
★★★★★★★★★★★★★★★★★」protected
클래스 멤버를 지정합니다.
새로운 어나니머스 기능을 활용한 좋은 질문과 기발한 아이디어!
흥미롭게도, 이것은 효과가 있습니다: 치환
$me->doSomething(); // Doesn't work
함수 자체에 대해 call_user_func를 실행합니다.
call_user_func($me->doSomething); // Works!
효과가 없는 것은 "올바른"
call_user_func(array($me, "doSomething")); // Doesn't work
그렇게 호출되면 PHP는 클래스 정의에서 메서드를 선언해야 합니다.
★★★★★★★★★★★★★★★★★★★★?private
public
protected
★★★★★★★★★★★★★★★★?
업데이트: 아니요.클래스 내에서도 정상이라고 할 수 없기 때문에, 이것은 가시성의 문제가 아닙니다.실제 기능 전달call_user_func()
내가 이 일을 해낼 수 있는 유일한 방법인 것 같아
함수를 배열에 저장할 수도 있습니다.
<?php
class Foo
{
private $arrayFuncs=array();// array of functions
//
public function addFunc($name,$function){
$this->arrayFuncs[$name] = $function;
}
//
public function callFunc($namefunc,$params=false){
if(!isset($this->arrayFuncs[$namefunc])){
return 'no function exist';
}
if(is_callable($this->arrayFuncs[$namefunc])){
return call_user_func($this->arrayFuncs[$namefunc],$params);
}
}
}
$foo = new Foo();
//Save function on array variable with params
$foo->addFunc('my_function_call',function($params){
return array('data1'=>$params['num1'],'data2'=>'qwerty','action'=>'add');
});
//Save function on array variable
$foo->addFunc('my_function_call2',function(){
return 'a simple function';
});
//call func 1
$data = $foo->callFunc('my_function_call',array('num1'=>1224343545));
var_dump($data);
//call func 2
$data = $foo->callFunc('my_function_call2');
var_dump($data);
?>
eval을 사용하는 방법을 보려면 github에서 사용할 수 있는 내 PHP 마이크로프레임워크 Halcyon을 살펴보세요.Halcyon Class Munger 클래스에 집중하여 문제없이 파악할 수 있을 정도로 작습니다.
★__call
솔루션에서는 (PHP > = 5.4)를 사용하여 메서드를 호출할 수 있습니다.$this
묶이다$me
음음음같 뭇매하다
call_user_func($me->doSomething->bindTo($me, null));
완전한 스크립트는 다음과 같습니다.
$me = new stdClass;
// Property for proving that the method has access to the above object:
$me->message = "I\'ve done something";
$me->doSomething = function () {
echo $this->message;
};
call_user_func($me->doSomething->bindTo($me)); // "I've done something"
" 함수"를 "바인드 함수"로 지정하지 않고 도 있습니다.call_user_func
:
$f = $me->doSomething->bindTo($me);
$f();
이 방법은 효과가 있었습니다.
$obj = new stdClass();
$obj->test = function(){
return 'Hi!';
};
return ($obj->test)();
stackoverflow에 대해서도 같은 글이 게재되어 있습니다.이것은, 특정의 설계 패턴의 실장에 의해서만 실현되는 것을 분명히 하고 있습니다.
다른 유일한 방법은 실험적인 php 확장자인 classkit을 사용하는 것입니다.(우편에도 있습니다)
예, 정의된 후 메서드를 PHP 클래스에 추가할 수 있습니다."실험적" 확장자인 클래스킷을 사용하려고 합니다.이 확장자는 기본적으로 활성화되어 있지 않기 때문에 커스텀 PHP 바이너리를 컴파일할 수 있는지, Windows에 있는 경우 PHP DLL을 로드할 수 있는지에 따라 달라집니다(예를 들어 Dreamhost는 커스텀 PHP 바이너리를 허용하며 셋업은 매우 용이합니다).
karim79 answer는 동작하지만 메서드 속성 내에 익명 함수를 저장하고 그의 선언은 같은 이름의 기존 속성을 덮어쓸 수 있거나 기존 속성이 다음과 같은 경우 작동하지 않습니다.private
치명적인 에러 오브젝트를 사용할 수 없게 됩니다.다른 어레이에 저장하고 세터를 사용하는 것이 더 깔끔한 해결책이라고 생각합니다.Method Injector setter는 특성을 사용하여 모든 객체에 자동으로 추가할 수 있습니다.
추신: 물론 SOLID의 Open Closed 원칙에 위배되므로 사용해서는 안 되는 해킹입니다.
class MyClass {
//create array to store all injected methods
private $anon_methods = array();
//create setter to fill array with injected methods on runtime
public function inject_method($name, $method) {
$this->anon_methods[$name] = $method;
}
//runs when calling non existent or private methods from object instance
public function __call($name, $args) {
if ( key_exists($name, $this->anon_methods) ) {
call_user_func_array($this->anon_methods[$name], $args);
}
}
}
$MyClass = new MyClass;
//method one
$print_txt = function ($text) {
echo $text . PHP_EOL;
};
$MyClass->inject_method("print_txt", $print_txt);
//method
$add_numbers = function ($n, $e) {
echo "$n + $e = " . ($n + $e);
};
$MyClass->inject_method("add_numbers", $add_numbers);
//Use injected methods
$MyClass->print_txt("Hello World");
$MyClass->add_numbers(5, 10);
언급URL : https://stackoverflow.com/questions/2938004/how-to-add-a-new-method-to-a-php-object-on-the-fly
'programing' 카테고리의 다른 글
Vuetify 2.2 DataTable 다중 필터 (0) | 2023.01.10 |
---|---|
실시간 업데이트를 기다린 후 값을 반환합니다 [Vuex , Firestore ] (0) | 2023.01.10 |
Matplotlib에서 선의 개별 점에 대한 표식기 설정 (0) | 2023.01.10 |
C 프리프로세서에서 Mac OS X, iOS, Linux, Windows를 신뢰성 있게 검출하는 방법 (0) | 2023.01.10 |
Programming Error: 스레드에서 생성된 SQLite 개체는 동일한 스레드에서만 사용할 수 있습니다. (0) | 2023.01.10 |