php: determina desde dónde se llamó a la función

93

¿Hay alguna manera de averiguar desde dónde se llamó a una función en PHP? ejemplo:

function epic()
{
  fail();
}

function fail()
{
  //at this point, how do i know, that epic() has called this function?
}
pol_b
fuente

Respuestas:

129

Puede utilizar debug_backtrace().

Ejemplo:

<?php

function epic( $a, $b )
{
    fail( $a . ' ' . $b );
}

function fail( $string )
{
    $backtrace = debug_backtrace();

    print_r( $backtrace );
}

epic( 'Hello', 'World' );

Salida:

Array
(
    [0] => Array
        (
            [file] => /Users/romac/Desktop/test.php
            [line] => 5
            [function] => fail
            [args] => Array
                (
                    [0] => Hello World
                )

        )

    [1] => Array
        (
            [file] => /Users/romac/Desktop/test.php
            [line] => 15
            [function] => epic
            [args] => Array
                (
                    [0] => Hello
                    [1] => World
                )

        )

)
romac
fuente
5
La primera vez que encontré debug_backtrace()una función excelente. ¡Usaré este!
David Yell
26

Utilizar debug_backtrace():

function fail()
{
    $backtrace = debug_backtrace();

    // Here, $backtrace[0] points to fail(), so we'll look in $backtrace[1] instead
    if (isset($backtrace[1]['function']) && $backtrace[1]['function'] == 'epic')
    {
        // Called by epic()...
    }
}
BoltClock
fuente
9
Eso definitivamente hace lo que quieres. Pero cuidado, debug_backtrace()es una llamada cara. No se acostumbre a usarlo para determinar cadenas de llamadas. Si desea "proteger" esas funciones, consulte OOP y métodos protegidos.
Ircmaxell
18

La solución más rápida y sencilla que encontré

public function func() { //function whose call file you want to find
    $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
}

$trace: Array
(
    [0] => Array
        (
            [file] => C:\wamp\www\index.php
            [line] => 56
            [function] => func
            [class] => (func Class namespace)
            [type] => ->
        )

)

Pruebo la velocidad en la computadora portátil Lenovo: Intel Pentiom CPU N3530 2.16GHz, RAM 8GB

global $times;
$start = microtime(true);
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
$times[] = microtime(true) - $start;

Resultados:

count($times):  97
min:    2.6941299438477E-5
max:   10.68115234375E-5
avg:    3.3095939872191E-5
median: 3.0517578125E-5
sum:  321.03061676025E-5

the same results with notation without E-5
count($times):  97
min:    0.000026941299438477
max:    0.0001068115234375
avg:    0.000033095939872191
median: 0.000030517578125
sum:    0.0032103061676025
Mariusz Charczuk
fuente
Para mí, DEBUG_BACKTRACE_IGNORE_ARGS fue muy útil, sin él, había demasiada información.
Arie
15

Entonces, si todavía REALMENTE no sabe cómo, aquí está la solución:

$backtrace = debug_backtrace();
echo 'Mu name is '.$backtrace[1]['function'].', and I have called him! Muahahah!';
marverix
fuente
1
Entonces podría usar if ($ backtrace [1] ['function'] == 'epic') {// hacer algunas cosas; más hacer algunas otras cosas; } ?? wow
Buttle Butkus
2
¡Sí, pero no lo hagas! No en el código de aplicación permanente, de todos modos. Utilice parámetros. debug_backtrace () parece una operación bastante pesada.
Kluny
3

Pruebe el siguiente código.

foreach(debug_backtrace() as $t) {              
   echo $t['file'] . ' line ' . $t['line'] . ' calls ' . $t['function'] . "()<br/>";
}
Makwana Ketan
fuente
Solución buena y directa para volver a rastrear todos los archivos desde los que se llama a una función en particular.
Excepción
3

Si desea rastrear el origen exacto de la llamada en la parte superior de la pila, puede usar el siguiente código:

$call_origin = end(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));

Esto ignorará las funciones encadenadas y obtendrá solo la información de llamada más relevante (relevante se usa libremente, ya que depende de lo que esté tratando de lograr).

Phillip Weber
fuente
Gracias.
Eso
-1
function findFunction($function, $inputDirectory=""){
    //version 0.1
    $docRoot = getenv("DOCUMENT_ROOT");
    $folderArray = null;
    $dirArray = null;

    // open directory
    $directory = opendir($docRoot.$inputDirectory);

    // get each entry
    while($entryName = readdir($directory)) {
        if(is_dir($entryName) && $entryName != "." && $entryName != ".."){
            $folderArray[] = str_replace($inputDirectory, "", $entryName);
        }
        $ext = explode(".", $entryName);
        if(!empty($ext[1])){
            $dirArray[] = $docRoot.$inputDirectory."/".$entryName;
        }
    }

    // close directory
    closedir($directory);
    $found = false;

    if(is_array($dirArray)){
        foreach($dirArray as $current){
            $myFile = file_get_contents($current);
            $myFile = str_replace("<?php", "", $myFile);
            $myFile = str_replace("?>", "", $myFile);
            if(preg_match("/function ".$function."/", $myFile)){
                $found = true;
                $foundLocation = $current;
                break;
            }
        }
    }
    if($found){
        echo $foundLocation;
        exit;
    } else if(is_array($folderArray)){
        foreach($folderArray as $folder){
            if(!isset($return)){
                $return = findFunction($function, $inputDirectory."/".$folder);
            } else if($return == false){
                $return = findFunction($function, $inputDirectory."/".$folder);
            }
        }
    } else {
        return false;
    }
}

findFunction("testFunction", "rootDirectory");

Espero que ayude a alguien. Si la función real está fuera de httpdocs, entonces no se puede encontrar porque el servidor se configurará para no permitirla. Solo lo probé en una carpeta de profundidad también, pero la metodología recursiva debería funcionar en teoría.

Esto es como la versión 0.1, pero no tengo la intención de continuar con el desarrollo, así que si alguien lo actualiza, no dude en volver a publicarlo.

Extraterrestre
fuente
Demasiado trabajo: agregue esto a .bashrc y function ff() { grep "function $1" $(find ./ -name "*.php") } luego llame a ff failo ff epic. ver: github.com/MaerF0x0/VimSetup/blob/master/bashrc#L122
Mike Graf