PHP 有没简单办法取到实参的名称? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
buxudashi
V2EX    PHP

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

  •  
  •   buxudashi Apr 27, 2023 3887 views
    This topic created in 1100 days ago, the information mentioned may be changed or developed.
    如题:
    function test($str){
    var_dump($str);
    }
    $user='xxx';
    test($user);

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

    }

    test($user);
    Xusually
        2
    Xusually  
       Apr 27, 2023 via iPhone
    最方便的办法是使用反射 ReflectionFunction 。
    当然你还可以使用 get_defined_vars()去查找。

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

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

    我刚刚用 debug_backtrace 写了个 php 取到调用时实参位置的内容。
    Rache1
        19
    Rache1  
       Apr 27, 2023
    需要安装 nikic/php-parser

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

    这里仅仅是提供一个思路
    user20190708
        23
    user20190708  
       Apr 27, 2023
    <?php
    $i = 1;
    function a($b) {
    $g = $GLOBALS;
    $v = array_keys($g);
    print_r(end($v));
    } a($i);
    Twislight
        24
    Twislight  
       Apr 27, 2023
    传两个参数,另一个是参数名
    asmoker
        25
    asmoker  
       Apr 27, 2023 via Android
    加 sentry
    8355
        26
    8355  
       Apr 27, 2023
    @asmoker #25 推荐楼主看看 方向错了就全错了 用这个 终于出现了
    @buxudashi #5
    akagishigeru
        27
    akagishigeru  
       Apr 27, 2023
    `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  
       Apr 27, 2023
    楼主你好,我给你实现了,代码如下:
    ```
    <?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  
       Apr 27, 2023
    抱歉,刚才的正则里面,函数名忘记写变量了,换为这个:
    ```
    preg_match("#{$lastStack['function']}\s*\((?P<params>.*)\)\s*;#", $lineStr, $matches);
    ```
    lisxour
        30
    lisxour  
       Apr 27, 2023
    你这一通乱搞还不如上分析工具和做好日志
    buxudashi
        31
    buxudashi  
    OP
       Apr 27, 2023
    看来都得根据文件所在行的行号才能取到了。
    buxudashi
        32
    buxudashi  
    OP
       Apr 27, 2023
    没更好的办法就散了。
    heysnakelis
        33
    heysnakelis  
       May 12, 2023
    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  
       May 12, 2023
    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
       May 12, 2023
    @heysnakelis 这个相当于传参时就传上去了。两个变量值相同时,这个查找是不对的。
    wxfjamdc
        36
    wxfjamdc  
       Jul 1, 2023
    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
       Jul 1, 2023
    @wxfjamdc
    不符合要求的。
    $a=5;
    foo($a), 我要得到 'a'这个字符串
    wxfjamdc
        38
    wxfjamdc  
       Jul 3, 2023
    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  
       Jul 3, 2023
    @wxfjamdc Ai 返回的,似乎也不行
    About     Help     Advertise     Blog     API     FAQ     Solana     2484 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 65ms UTC 04:01 PVG 12:01 LAX 21:01 JFK 00:01
    Do have faith in what you're doing.
    ubao msn 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