wsug
1
问题复现代码如下:
$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遍历类中所有公共属性,用判断属性名的方法可以调用这个由数组转换成的类中的函数,但不能每次调用函数时都写个循环。
用->
调用类中的变量是没问题的,但类中的公开方法应该怎么调用(不写循环情况下)?
wsug
2
刚刚终于通过了某站 提问的智慧
测试,感觉这通关难度还是不小的。相比之下,感觉还是本站好多了,管理员们都是非常好讲话的
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 个赞
wsug
7
感谢大家的回复,再次请教大佬,我数组定义时习惯用-
作分割符,比如$arr["org-mode"]="最好的笔记工具";
,这样转成对象后,对象的公共属性里也有用-
分割的属性,可以用循环的方式调用到。
但是不符合php命名规则,用->
调用时命名中有-号就报错。但对象中确实是有这个公共属性|方法的,这个又要如何才能调用得了这些属性|方法
wsug
8
LearnKu
不错,这个问题同步到LearnKu去了,还在评论里说了 我是emacs用户
wsug
9
LearnKu那边有给出办法了,用花括号: $obj->{"org-mode"}
可行,学到了