buxudashi
V2EX  ›  PHP

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

  •  
  •   buxudashi · Apr 27, 2023 · 4601 views
    This topic created in 1291 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
    SelectLanguages
    Apr 27, 2023
    1
    ????
    $user='xxx';
    function test($str){
    if($str){
    }else{
    var_dump($user);
    }

    }

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

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

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

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

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

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