[php问题] 如何调用由数组转换成的类中的方法?

问题复现代码如下:

$arr["t"]="123";
$arr["fn"]=function(){
  echo "这个函数调用了";
};
$obj=(object)$arr;
foreach($obj as $f=>$v){ //遍历类中所有公共属性
  if($f=="fn"){
    $v();//成功调用到类中的函数
  }
}
echo $obj->t;//这样调用类中的变量是没问题的
$obj->fn();//但调用类中的方法不行

我用foreach遍历类中所有公共属性,用判断属性名的方法可以调用这个由数组转换成的类中的函数,但不能每次调用函数时都写个循环。

->调用类中的变量是没问题的,但类中的公开方法应该怎么调用(不写循环情况下)?

刚刚终于通过了某站 提问的智慧 测试,感觉这通关难度还是不小的。相比之下,感觉还是本站好多了,管理员们都是非常好讲话的

1 个赞

这样即可调用:

($obj->fn)()

因为这里 fn 不是 $obj 的方法($obj 的类型是 stdClass,没有方法), 而是一个类型为 Closure 的属性。

反编译一下这段 PHP 字节码可以看到:

L0002 0000 ASSIGN_DIM CV0($arr) string("t")
L0002 0001 OP_DATA string("123")
L0003 0002 T6 = DECLARE_LAMBDA_FUNCTION 0
L0003 0003 ASSIGN_DIM CV0($arr) string("fn")
L0005 0004 OP_DATA T6
L0006 0005 T7 = CAST (object) CV0($arr)
L0006 0006 ASSIGN CV1($obj) T7
L0007 0007 V9 = FE_RESET_R CV1($obj) 0015
L0007 0008 T10 = FE_FETCH_R V9 CV2($v) 0015
L0007 0009 ASSIGN CV3($f) T10
L0008 0010 T12 = IS_EQUAL CV3($f) string("fn")
L0008 0011 JMPZ T12 0014
L0009 0012 INIT_DYNAMIC_CALL 0 CV2($v)
L0009 0013 DO_FCALL
L0007 0014 JMP 0008
L0007 0015 FE_FREE V9
L0012 0016 T14 = FETCH_OBJ_R CV1($obj) string("t")
L0012 0017 ECHO T14
L0013 0018 INIT_METHOD_CALL 0 CV1($obj) string("fn")
L0013 0019 DO_FCALL
L0014 0020 RETURN int(1)

从 L0013 可以看出,是一个方法调用。

如果改成 ($obj->fn)() 的写法,则是:

L0013 0018 T15 = FETCH_OBJ_R CV1($obj) string("fn")
L0013 0019 INIT_DYNAMIC_CALL 0 T15
L0013 0020 DO_FCALL

也就是对成员变量进行“调用”这一操作。

3 个赞

另:建议到 LearnKu(曾经的 Laravel China 论坛,全国最大的 PHP 社区)讨论 PHP 问题。

本论坛使用 PHP 的玩家应该不多

感谢,确实如此

还可以用 call_user_func / call_user_func_array

#+BEGIN_SRC php :results output
<?php
$arr["t"]="123";
$arr["fn"]=function(){
  echo "这个函数调用了";
};
$obj=(object)$arr;
call_user_func($obj->fn);
#+END_SRC

#+RESULTS:
: 这个函数调用了
1 个赞

感谢大家的回复,再次请教大佬,我数组定义时习惯用-作分割符,比如$arr["org-mode"]="最好的笔记工具";,这样转成对象后,对象的公共属性里也有用-分割的属性,可以用循环的方式调用到。

但是不符合php命名规则,用->调用时命名中有-号就报错。但对象中确实是有这个公共属性|方法的,这个又要如何才能调用得了这些属性|方法

LearnKu不错,这个问题同步到LearnKu去了,还在评论里说了 我是emacs用户

LearnKu那边有给出办法了,用花括号: $obj->{"org-mode"}可行,学到了