У меня есть функция вне моего класса, и я call_user_func
ее изнутри с помощью call_user_func
, моя проблема в том, что я не могу использовать класс доступа внутри функции. Мне нужен способ доступа к моему классу, не передавая его в аргументы, если бы был способ сделать $this
работу внутри функции, которая была бы замечательной.
Любые советы, кроме передачи класса с аргументом в функцию, будут оценены;
function test($arg1) { $this->code = 10; // i know $this won't work here, // but i need a way to change $code // property from this function without // passing class into this function by using arguments } class MyClass { public $code; public function call() { call_user_func("test", "argument1"); } }
Если вы можете переместить функцию внутри своего класса, вы можете вызвать ее так:
call_user_func(array($this, 'the_function'));
Если у вас есть PHP5.3, вы можете использовать закрытие:
$that = $this; $function = function() use ($that) { // use $that instead of $this }; call_user_func($function);
Если вы можете добавить аргумент, вы можете сделать следующее:
call_user_func('the_function', "argument1", $this);
Передайте $this
как первый параметр, если функция запрашивает его:
(Если функция имеет параметр с именем $__this
, передайте $this
как параметр)
function the_function($__this, $foo, $bar) { } $arguments = array('argument1'); $function = new ReflectionFunction('the_function'); $params = $function->getParameters(); if (count($params) > 0 && $params[0]->name == '__this') { array_unshift($arguments, $this); } $function->invokeArgs($arguments);
Вы можете сделать то же самое с комментариями doc:
/** * @IWantThis */ function the_function($__this) { } $function = new ReflectionFunction('the_function'); if (preg_match('/@IWantThis/', $function->getDocComment()) { ...
Непосредственно у вас есть два варианта: либо передача объекта в функцию, либо значение для объекта . Я понятия не имею, если это единственное задание, которое выполняет функция, поэтому это может не решить вашу проблему, просто показывая альтернативу, поскольку вы написали, что передача объекта функции не является вариантом:
function test($arg1) { return 10; } class MyClass { public $code; public function call() { $this->code = call_user_func("test", "argument1"); } }
Если вы не хотите ни одного из них, вы должны создать некоторый контекст, как объект, так и функция, работать, чтобы соединяться друг с другом.
Вы можете создавать контекст статически или динамически. Первый часто связан с глобальными переменными, что может привести к сложному поддержанию кода с течением времени, например:
function test($arg1) { global $object; $object->code = 10; } class MyClass { public $code; public function call() { global $object; $object = $this; call_user_func("test", "argument1"); unset($object); } }
сfunction test($arg1) { global $object; $object->code = 10; } class MyClass { public $code; public function call() { global $object; $object = $this; call_user_func("test", "argument1"); unset($object); } }
Чтобы создать более динамический контекст, вы инкапсулируете все в какой-то контекст:
class contextCallback { private $object; public function __construct($object) { $this->object = $object; } public function test() { $this->object = 10; } } class MyClass { public $code; public function call() { $callback = new contextCallback($this); call_user_func(array($callback, 'test'), "argument1"); # or: $callback->test("argument1"); } }
Однако я думаю, что передача $this
в качестве аргумента намного проще и почти то же самое с гораздо меньшим количеством кода. Я понятия не имею, почему вам нужен call_user_func
поэтому он остается абстрактным.
Изменить: в качестве другой альтернативы и отделить от конкретных классов, когда вам нужно только установить значения, рассмотрите возможность возврата нескольких значений:
function test($arg1) { $object->code = 10; return array($value, $object); } class MyClass { public $code; public function call() { list($value, $object) = call_user_func("test", "argument1"); foreach($object as $var => $value) $this->$var = $value; } }
У вас есть два варианта. Сделайте метод методом объекта MyClass
или сделайте объект параметром функции.
Если у вас есть функция, вы хотите, чтобы она делала то же самое, каждый раз. Это означает, что если функция зависит от некоторого состояния (например, значение $this
), вам нужно найти способ либо 1. сделать его глобальным (не здесь), либо 2. передать его в качестве параметра.
Вы все равно не нуждаетесь в $this
в этой функции, вам нужен какой-то объект, который имеет атрибут, названный любым содержимым $code
(я думаю, что это опечатка на самом деле. Я думаю, вы имеете в виду $this->code
не $this->$code
).
Вы можете использовать закрытие (php 5.3+), чтобы «передать» ссылку на объект тем функциям, которые в ней нуждаются.
Но вам нужно будет сделать разницу между «старыми» функциями и «новыми» функциями расширения. И новые функции по-прежнему имеют доступ к общедоступным свойствам / методам объекта.
<?php class MyClass { public $code = 0; protected $functions=array(); public function call($fn) { if ( is_string($fn) && isset($this->functions[$fn]) ) { $fn = $this->functions[$fn]; } if ( !is_callable($fn) ) { die('add error handler here'); } $rv = call_user_func($fn, 'argument1'); } public function loadFunctions($file) { $fnInit = require $file; $fns = $fnInit($this); $this->functions = array_merge($this->functions, $fns); } } $m = new MyClass; $m->loadFunctions('ext.php'); $m->call('oldFn'); $m->call('foo'); $m->call('bar'); echo 'and now $m->code is: ', $m->code;
и как ext.php:
<?php function oldFn($arg) { // that's probably all you have to do atm to have a new "extension function" for your class echo "oldFn($arg)\n"; } return function($obj) { // and that's more or less how the new functions would have to be declared/defined return array( 'foo'=>function($arg1) use($obj) { echo "foo($arg1) + code: $obj->code\n"; $obj->code = 1; }, 'bar'=>function($arg1) use($obj) { echo "bar($arg1) + code: $obj->code\n"; $obj->code = 2; } ); };
печать
oldFn(argument1) foo(argument1) + code: 0 bar(argument1) + code: 1 and now $m->code is: 2
(если это кажется вам чем-то возможным, я могу написать немного больше текста … но не сейчас ;-))
call_user_func("test", array($this,"argument1"));
Я не 100%, но вы должны иметь доступ к нему с помощью
function test($arg1) { $arg1[0]->code = 10; }
Будет ли runkit
соответствовать вашим потребностям, в частности runkit_function_redefine
?