PHP 有没简单办法取到实参的名称? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
buxudashi
V2EX    PHP

PHP 有没简单办法取到实参的名称?

  •  
  •   buxudashi 2023-04-27 07:55:05 +08:00 3333 次点击
    这是一个创建于 898 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如题:
    function test($str){
    var_dump($str);
    }
    $user='xxx';
    test($user);

    怎么能在 test 函数内,取到'user'这个字符串。它是实参的名称。
    39 条回复    2023-07-03 10:40:01 +08:00
    SelectLanguages
        1
    SelectLanguages  
       2023-04-27 08:00:23 +08:00
    ????
    $user='xxx';
    function test($str){
    if($str){
    }else{
    var_dump($user);
    }

    }

    test($user);
    Xusually
        2
    Xusually  
       2023-04-27 08:05:01 +08:00 via iPhone
    最方便的办法是使用反射 ReflectionFunction 。
    当然你还可以使用 get_defined_vars()去查找。

    能问下你的场景吗,很少有人需要这么做,在做日志工具?
    buxudashi
        3
    buxudashi  
    OP
       2023-04-27 08:09:24 +08:00
    @Xusually 就是简单的保存下调用者的变量名。这样报错时,直接全局查找这个名就知道哪里错了。test 其实是个全局的异常用。
    awinds
        4
    awinds  
       2023-04-27 08:39:18 +08:00
    报错堆栈信息不是有行号吗?
    buxudashi
        5
    buxudashi  
    OP
       2023-04-27 08:40:06 +08:00
    @awinds 跑题了。异常不一定非得报错。
    chancefyi
        6
    chancefyi  
       2023-04-27 08:42:48 +08:00
    func_get_args()
    buxudashi
        7
    buxudashi  
    OP
       2023-04-27 08:44:13 +08:00
    @chancefyi 这个是以 0 开始索引的参数。取不到名称。
    user20190708
        8
    user20190708  
       2023-04-27 09:09:11 +08:00 via iPhone
    据我所知是拿不到
    zlhsvc
        9
    zlhsvc  
       2023-04-27 09:12:59 +08:00
    异常可以自动捕获写入日志的啊,日志打印堆栈信息不就好了,你这操作有点看不明白
    suyuyu
        10
    suyuyu  
       2023-04-27 09:13:33 +08:00
    能拿到的。以前我也搞过记不清了你试试是不是 debug_backtrace
    1343EFF
        11
    1343EFF  
       2023-04-27 09:14:01 +08:00
    直接上 try
    8355
        12
    8355  
       2023-04-27 09:15:09 +08:00
    传入之后就是值拷贝了
    咋能取到呢。。。
    QlanQ
        13
    QlanQ  
       2023-04-27 09:17:49 +08:00
    调用者给的变量名都是不一样的?
    异常的捕获和报错不冲突呀
    encro
        14
    encro  
       2023-04-27 09:18:16 +08:00
    正确的方法:

    直接抛出异常,在外层捕获异常,然后就能获得异常的 trace 。
    buxudashi
        15
    buxudashi  
    OP
       2023-04-27 09:18:49 +08:00
    @suyuyu debug_backtrace 这个不行的。反射也不行的。但是有人宣称可以有办法拿到。所以来问。
    buxudashi
        16
    buxudashi  
    OP
       2023-04-27 09:20:03 +08:00
    @encro 不考虑异常的问题,就单纯的想取到实参的名称。
    encro
        17
    encro  
       2023-04-27 09:23:20 +08:00
    取不到。。。
    zjsxwc
        18
    zjsxwc  
       2023-04-27 09:23:26 +08:00
    https://gist.github.com/zjsxwc/970216c64d7cc5905e86a0d17f62bbb2

    我刚刚用 debug_backtrace 写了个 php 取到调用时实参位置的内容。
    Rache1
        19
    Rache1  
       2023-04-27 09:31:12 +08:00
    需要安装 nikic/php-parser

    https://3v4l.org/elVlX
    user20190708
        20
    user20190708  
       2023-04-27 09:31:59 +08:00 via iPhone
    看 $GLOBALS 有这个名字,研究下咋取出来?
    angryPHP
        21
    angryPHP  
       2023-04-27 09:32:34 +08:00
    为什么会有这种需求
    Rache1
        22
    Rache1  
       2023-04-27 09:38:09 +08:00
    @Rache1 这个很简陋,实际上最好还要根据 debug_backtrace 提供的行号、位置信息与 php-parser 解析出来的行号位置进行比较一下,按照例子里面的,如果同一个函数在一个文件里面调用了多次,就只有第一次会被获取到了。而且这个只是简单的对函数调用进行了处理,对于方法调用没有处理。

    这里仅仅是提供一个思路
    user20190708
        23
    user20190708  
       2023-04-27 09:40:38 +08:00
    <?php
    $i = 1;
    function a($b) {
    $g = $GLOBALS;
    $v = array_keys($g);
    print_r(end($v));
    } a($i);
    Twislight
        24
    Twislight  
       2023-04-27 09:42:39 +08:00
    传两个参数,另一个是参数名
    asmoker
        25
    asmoker  
       2023-04-27 09:55:32 +08:00 via Android
    加 sentry
    8355
        26
    8355  
       2023-04-27 09:56:57 +08:00
    @asmoker #25 推荐楼主看看 方向错了就全错了 用这个 终于出现了
    @buxudashi #5
    akagishigeru
        27
    akagishigeru  
       2023-04-27 10:28:24 +08:00
    `sf `上有人提过,可以试试
    ```php
    function test($str){
    $trace = debug_backtrace();
    $vLine = file( __FILE__ );
    $fLine = $vLine[ $trace[0]['line'] - 1 ];
    preg_match( "#\\$(\w+)#", $fLine, $match );
    print_r( $match );
    }
    ```
    brader
        28
    brader  
       2023-04-27 10:39:05 +08:00
    楼主你好,我给你实现了,代码如下:
    ```
    <?php

    function test($str)
    {
    var_dump($str);
    // 调用此函数堆栈
    $stack = xdebug_get_function_stack();
    $lastStack = array_pop($stack);
    // print_r($lastStack);
    $lineStr = getLine($lastStack['file'], $lastStack['line']);
    // print_r($lineStr);
    // 正则提取参数
    preg_match('#test\s*\((?P<params>.*)\)\s*;#', $lineStr, $matches);
    // 格式化参数
    $params = explode(',', $matches['params']);
    $params = array_map('trim', $params);
    print_r($params);

    }

    $user = 'xxx';
    test($user);

    /**
    * 读取文件指定行内容
    * @param $file
    * @param $line
    * @param int $length
    * @return false|string|null
    */
    function getLine($file, $line, $length = 4096)
    {
    $returnTxt = null; // 初始化返回
    $i = 1; // 行数
    $handle = @fopen($file, "r");
    if ($handle) {
    while (!feof($handle)) {
    $buffer = fgets($handle, $length);
    if ($line == $i) {
    $returnTxt = $buffer;
    break;
    }
    $i++;
    }
    fclose($handle);

    }
    return $returnTxt;
    }
    ```
    brader
        29
    brader  
       2023-04-27 10:44:28 +08:00
    抱歉,刚才的正则里面,函数名忘记写变量了,换为这个:
    ```
    preg_match("#{$lastStack['function']}\s*\((?P<params>.*)\)\s*;#", $lineStr, $matches);
    ```
    lisxour
        30
    lisxour  
       2023-04-27 11:36:21 +08:00
    你这一通乱搞还不如上分析工具和做好日志
    buxudashi
        31
    buxudashi  
    OP
       2023-04-27 12:48:23 +08:00
    看来都得根据文件所在行的行号才能取到了。
    buxudashi
        32
    buxudashi  
    OP
       2023-04-27 22:59:02 +08:00
    没更好的办法就散了。
    heysnakelis
        33
    heysnakelis  
       2023-05-12 18:02:26 +08:00
    public static function get_variable_name($var, $scope)
    {
    $name = array_search($var, $scope, true); // 根据值查找变量名称
    return $name;
    }


    public static function printVar($var, $scope)
    {
    $name = self::get_variable_name($var, $scope);
    print_r([$name => $var]);
    }
    heysnakelis
        34
    heysnakelis  
       2023-05-12 18:03:23 +08:00
    Tool::printVar($get_params_1, get_defined_vars());
    class Tool
    {
    public static function get_variable_name($var, $scope)
    {
    $name = array_search($var, $scope, true); // 根据值查找变量名称
    return $name;
    }


    public static function printVar($var, $scope)
    {
    $name = self::get_variable_name($var, $scope);
    print_r([$name => $var]);
    }


    }
    buxudashi
        35
    buxudashi  
    OP
       2023-05-12 18:33:00 +08:00
    @heysnakelis 这个相当于传参时就传上去了。两个变量值相同时,这个查找是不对的。
    wxfjamdc
        36
    wxfjamdc  
       2023-07-01 14:14:23 +08:00
    function foo($a, $b, $c) {
    $ref = new ReflectionFunction(__FUNCTION__);
    $params = $ref->getParameters();
    foreach ($params as $param) {
    echo $param->getName() . "\n";
    }
    }

    foo(1, 2, 3);
    buxudashi
        37
    buxudashi  
    OP
       2023-07-01 17:45:09 +08:00
    @wxfjamdc
    不符合要求的。
    $a=5;
    foo($a), 我要得到 'a'这个字符串
    wxfjamdc
        38
    wxfjamdc  
       2023-07-03 10:23:38 +08:00
    function foo($a, $b, $c) {
    $trace = debug_backtrace();
    $args = $trace[0]['args'];
    print_r($args);
    }

    $actualArgument = 1;
    foo($actualArgument, 2, 3);

    只能在 PHP 8.0 或更高版本中使用,因为在之前的版本中,debug_backtrace()函数返回的数组中的 args 元素是实参的值,而不是名称。另外,这种方法也只能在实参是变量的情况下使用,如果实参是常量或表达式,那么返回的名称将是它们的值。
    wxfjamdc
        39
    wxfjamdc  
       2023-07-03 10:40:01 +08:00
    @wxfjamdc Ai 返回的,似乎也不行
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5843 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 06:35 PVG 14:35 LAX 23:35 JFK 02:35
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86