如何添加一個新的方法「對飛」的對象?如何將一個新方法添加到一個php對象上?
$me= new stdClass;
$me->doSomething=function()
{
echo 'I\'ve done something';
};
$me->doSomething();
//Fatal error: Call to undefined method stdClass::doSomething()
如何添加一個新的方法「對飛」的對象?如何將一個新方法添加到一個php對象上?
$me= new stdClass;
$me->doSomething=function()
{
echo 'I\'ve done something';
};
$me->doSomething();
//Fatal error: Call to undefined method stdClass::doSomething()
您可以利用__call
此:
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();
非常,非常聰明,但在現實世界項目海事組織! (和+1反擊匿名downvoter) – 2010-05-30 09:07:08
@pekka - 但是,確切地說,它是如何?當然,我並不是說我是運行時在PHP中擴展對象的專家,但我真的不能說我看到了很多錯誤。 (也許我只是口味不佳) – karim79 2010-05-30 09:13:50
@karim這只是一般的感覺,它不是'__call'的意圖,它可能已經被使用。從編碼風格的角度來看,我會感到不安。另一方面,它*是優雅的,可以通過錯誤檢查進行擴展(比如'$ method'不存在時),並且可以在某個核心類中定義,然後傳遞給所有對象。 – 2010-05-30 09:17:26
要了解如何與EVAL做到這一點,你可以看看我的PHP微架構,太平,這是可以的github。它足夠小,您應該能夠毫無問題地找出它 - 專注於HalcyonClassMunger類。
更新:此處顯示的方法有很大的缺點:新功能不是類的完全合格的成員;當以這種方式調用時,方法中不存在
$this
。這意味着,如果您想使用對象實例中的數據或函數,則必須將該對象作爲參數傳遞給該函數!此外,您將無法從這些函數訪問類的private
或protected
成員。
很好的問題,巧妙的構思用新的匿名功能!
有趣的是,這個工程:
call_user_func($me->doSomething); // Works!
什麼行不通是 「正確」 的方式:
call_user_func(array($me, "doSomething")); // Doesn't work
通過call_user_func
對函數本身更換
$me->doSomething(); // Doesn't work
如果以這種方式調用,PHP需要將方法聲明爲類定義。
這是private
/public
/protected
可見性問題?
更新:都能跟得上。即使在課堂內部也不可能以正常的方式調用函數,所以這不是一個可見性問題。將實際功能傳遞給call_user_func()
是我看起來能夠完成這項工作的唯一方法。
有一個similar post on stackoverflow掃清指出,這是隻有通過一定的設計模式的實現可以實現的。
唯一的另一種方式是通過使用classkit,這是一個實驗性的php擴展。 (也在帖子中)
是的,可以在PHP類定義後向 添加方法。您 要使用classkit,這是一個 「實驗性」的延伸。看來 ,這種擴展是不是 但是默認情況下啓用,所以這取決於如果 ,您可以編輯自定義的PHP程序或Windows 負載PHP的DLL,如果決定(例如 Dreamhost的確實允許自定義 PHP二進制文件,他們'非常容易 設置)。
這裏有一個簡單的類,允許設置匿名函數。這是一個優化類的https://gist.github.com/nickunderscoremok/5857846
<?php
class stdObject {
public function __construct(array $arguments = array()) {
if (!empty($arguments)) {
foreach ($arguments as $property => $argument) {
if ($argument instanceOf Closure) {
$this->{$property} = $argument;
} else {
$this->{$property} = $argument;
}
}
}
}
public function __call($method, $arguments) {
if (isset($this->{$method}) && is_callable($this->{$method})) {
return call_user_func_array($this->{$method}, $arguments);
} else {
throw new Exception("Fatal error: Call to undefined method stdObject::{$method}()");
}
}
}
$person = new stdObject(array(
"name" => "nick",
"age" => 23,
"friends" => array("frank", "sally", "aaron"),
"sayHi" => function() {
return "Hello there";
}
));
$person->sayHi2 = function() {
return "Hello there 2";
};
$person->test = function() {
return "test";
};
var_dump($person->name, $person->test(), $person->sayHi2());
?>
if($ argument instanceOf Closure){$ this - > {$ property} = $ argument;其他{ $ this - > {$ property} = $ argument; }是無意義的條件。 – Kzqai 2016-08-29 19:25:10
,以便允許在運行時添加新的方法具有重大的缺點,這些方法不能使用這個實例引用$使用簡單__call。 一切都很好,直到添加的方法不在代碼中使用$ 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
爲了解決THI問題,您可以重寫的圖案以這種方式
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"
你也可以將功能保存在一個陣列中:
<?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);
?>
隨着PHP7可以使用匿名類
$myObject = new class {
public function myFunction(){}
};
$myObject->myFunction();
這幫了我。非常感謝。 – 2017-10-05 09:47:18
沒有__call
溶液,可以使用bindTo
(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();
我永遠不會使用它,語法是可怕的,但你可以添加具有功能的對象屬性。靜態時儘可能保存打字新和();
class SomeFuncs{ static function a(){ /* do something */ }}
$o = new stdClass();
$o->f = SomeFuncs;
$o->f::a();
karim79解答工作但是它存儲匿名函數方法屬性裏面,他的聲明可以覆蓋現有的同名屬性或不工作,如果現有的屬性是private
導致致命的錯誤對象無法使用,我認爲它們存儲在單獨的數組和使用setter是更清潔的解決方案。使用traits可自動將方法注射器設置器添加到每個對象。
P.S.當然這是不應該使用的破解,因爲它違反了SOLID的開放式封閉原則。
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);
這是不是專門沒有使用類? – 2011-07-20 07:42:01
您可以使用__call。但請不要使用__call。動態地改變一個對象的行爲是一個非常簡單的方法,使你的代碼不可讀和不可維護。 – GordonM 2017-01-03 14:49:20
你可以使用這個工具:https://packagist.org/packages/drupol/dynamicobjects – 2017-09-19 14:45:29