Функции переменных
PHP поддерживает концепцию функций переменных. Это означает, что
если к имени переменной присоединили круглые скобки, PHP ищет
функцию с тем же именем, что и результат вычисления переменной,
и пробует выполнить функцию. Этим синтаксисом
описывают callback-функции, таблицы функций и т. д.
Функции переменных не работают с языковыми конструкциями
echo, print,
unset(), isset(),
empty(), include,
require и т. п.
Напишите функцию-обёртку, чтобы эти конструкции работали как функции переменных.
Пример #1 Пример функции переменной
<?php
function foo() {
echo "В foo()\n";
}
function bar($arg = '')
{
echo "В bar(); аргумент был '$arg'.\n";
}
// Функция-обёртка для echo
function echoit($string)
{
echo $string;
}
$func = 'foo';
$func(); // Вызывает функцию foo()
$func = 'bar';
$func('test'); // Вызывает функцию bar()
$func = 'echoit';
$func('test'); // Вызывает функцию echoit()
Синтаксис функций переменных работает также для вызова методов объектов.
Пример #2 Пример метода переменной
<?php
class Foo
{
function Variable()
{
$name = 'Bar';
$this->$name(); // Вызывает метод Bar()
}
function Bar()
{
echo "Это Bar";
}
}
$foo = new Foo();
$funcname = "Variable";
$foo->$funcname(); // Вызывает $foo->Variable()
При вызове статических методов вызов функции «сильнее»,
чем оператор доступа к статическому свойству:
Пример #3 Пример вызова метода переменной со статическим свойством
<?php
class Foo
{
static $variable = 'статическое свойство';
static function Variable()
{
echo "Вызов метода Variable\n";
}
}
echo Foo::$variable ."\n"; // Это выведет «статическое свойство». В области видимости класса нужна переменная $variable
$variable = "Variable";
Foo::$variable(); // Вызывает $foo->Variable() после прочтения переменной $variable в текущей области видимости
Результат выполнения приведённого примера:
статическое свойство
Вызов метода Variable
Пример #4 Сложные callable-функции
<?php
class Foo
{
static function bar()
{
echo "bar\n";
}
function baz()
{
echo "baz\n";
}
}
$func = array("Foo", "bar");
$func(); // Выведет "bar"
$func = array(new Foo(), "baz");
$func(); // Выведет "baz"
$func = "Foo::bar";
$func(); // Выведет "bar"
niemans at pbsolo dot nl ¶7 years ago
While the documentation suggests that the use of a constant is similar to the use of a variable, there is an exception regarding variable functions. You cannot use a constant as the function name to call a variable function.
const DEBUGME ='func';
function func($s) { echo $s. "\n"; }
DEBUGME('abc'); // results in a syntax error
$call = DEBUGME;
$call('abc'); // does the job
But you can use a constant as an argument to a function. Here's a simple workaround when you need to call a variable constant function:
function dynamic($what, $with)
{
$what($with);
}
dynamic(DEBUGME, 'abc');
This makes sense to me to hide API's and/or long (complicated) static calls.
Enjoy!
Anonymous ¶14 years ago
$ wget http://www.php.net/get/php_manual_en.tar.gz/from/a/mirror
$ grep -l "\$\.\.\." php-chunked-xhtml/function.*.html
List of functions that accept variable arguments.
<?php
array_diff_assoc()
array_diff_key()
array_diff_uassoc()
array()
array_intersect_ukey()
array_map()
array_merge()
array_merge_recursive()
array_multisort()
array_push()
array_replace()
array_replace_recursive()
array_unshift()
call_user_func()
call_user_method()
compact()
dba_open()
dba_popen()
echo()
forward_static_call()
fprintf()
fscanf()
httprequestpool_construct()
ibase_execute()
ibase_set_event_handler()
ibase_wait_event()
isset()
list()
maxdb_stmt_bind_param()
maxdb_stmt_bind_result()
mb_convert_variables()
newt_checkbox_tree_add_item()
newt_grid_h_close_stacked()
newt_grid_h_stacked()
newt_grid_v_close_stacked()
newt_grid_v_stacked()
newt_win_choice()
newt_win_entries()
newt_win_menu()
newt_win_message()
newt_win_ternary()
pack()
printf()
register_shutdown_function()
register_tick_function()
session_register()
setlocale()
sprintf()
sscanf()
unset()
var_dump()
w32api_deftype()
w32api_init_dtype()
w32api_invoke_function()
wddx_add_vars()
wddx_serialize_vars()
?>
rnealxp at yahoo dot com ¶6 years ago
<?php
interface iface_dynamic_members{
public function __call($name, $args);
public function __set($name, $value);
public function quietly_fail():bool;
}
trait trait_has_dynamic_members{
public function __call($name, $args) {
if (is_callable($this->$name)) {
return call_user_func($this->$name, $args);
}
else {
if($this->quietly_fail()===true){
echo 'Method does not exist, but I do not mind.';
}else{
echo 'Method does not exist, I consider this a bug.';
}
}
}
public function __set($name, $value) {
$this->$name = is_callable($value) ? $value->bindTo($this, $this): $value; }
}
abstract class MBR_ATTR{
public static function is_a_walker(iface_dynamic_members $obj, ?string $walker_type='normal pace'){
$obj->walker_type = $walker_type;
$obj->walker_walk = function() {
return "I am walking {$this->walker_type}.";
};
}
public static function is_a_runner(iface_dynamic_members $obj, string $runner_type){
$obj->runner_type = $runner_type;
$obj->runner_run = function() {
return "I am running {$this->runner_type}.";
};
self::is_a_walker($obj); }
}
class cls_partly_dynamic implements iface_dynamic_members{
use trait_has_dynamic_members;
public function quietly_fail():bool{
return true;
}
}
error_reporting(E_ALL & ~E_NOTICE); $obj_runner = new cls_partly_dynamic();
MBR_ATTR::is_a_runner($obj_runner, 'fast');
$obj_runner->runner_type = 'a bit slow';
$obj_walker = new cls_partly_dynamic();
MBR_ATTR::is_a_walker($obj_walker, 'slow');
$obj_walker->walker_type = 'super fast';
echo 'walker in action...' . '<br>';
echo $obj_walker->walker_walk() . '<br>';
echo '<br>';
echo 'runner in action...' . '<br>';
echo $obj_runner->walker_walk() . '<br>';
echo $obj_runner->runner_run() . '<br>';
echo $obj_runner->xxx() . '<br>'; ?>