V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
buxudashi
V2EX  ›  PHP

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

  •  
  •   buxudashi · 336 天前 · 2252 次点击
    这是一个创建于 336 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如题:
    function test($str){
    var_dump($str);
    }
    $user='xxx';
    test($user);

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

    }

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

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

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

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

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

    这里仅仅是提供一个思路
    user20190708
        23
    user20190708  
       336 天前
    <?php
    $i = 1;
    function a($b) {
    $g = $GLOBALS;
    $v = array_keys($g);
    print_r(end($v));
    } a($i);
    Twislight
        24
    Twislight  
       336 天前
    传两个参数,另一个是参数名
    asmoker
        25
    asmoker  
       336 天前 via Android
    加 sentry
    8355
        26
    8355  
       336 天前
    @asmoker #25 推荐楼主看看 方向错了就全错了 用这个 终于出现了
    @buxudashi #5
    JaguarJack
        27
    JaguarJack  
       336 天前
    `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  
       336 天前
    楼主你好,我给你实现了,代码如下:
    ```
    <?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  
       336 天前
    抱歉,刚才的正则里面,函数名忘记写变量了,换为这个:
    ```
    preg_match("#{$lastStack['function']}\s*\((?P<params>.*)\)\s*;#", $lineStr, $matches);
    ```
    lisxour
        30
    lisxour  
       336 天前
    你这一通乱搞还不如上分析工具和做好日志
    buxudashi
        31
    buxudashi  
    OP
       336 天前
    看来都得根据文件所在行的行号才能取到了。
    buxudashi
        32
    buxudashi  
    OP
       336 天前
    没更好的办法就散了。
    heysnakelis
        33
    heysnakelis  
       321 天前
    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  
       321 天前
    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
       321 天前
    @heysnakelis 这个相当于传参时就传上去了。两个变量值相同时,这个查找是不对的。
    wxfjamdc
        36
    wxfjamdc  
       271 天前
    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
       271 天前
    @wxfjamdc
    不符合要求的。
    $a=5;
    foo($a), 我要得到 'a'这个字符串
    wxfjamdc
        38
    wxfjamdc  
       269 天前
    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  
       269 天前
    @wxfjamdc Ai 返回的,似乎也不行
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1184 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 18:22 · PVG 02:22 · LAX 11:22 · JFK 14:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.