php: déterminer d'où la fonction a été appelée

93

y a-t-il un moyen de savoir d'où vient une fonction en PHP? exemple:

function epic()
{
  fail();
}

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

Réponses:

129

Vous pouvez utiliser debug_backtrace().

Exemple:

<?php

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

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

    print_r( $backtrace );
}

epic( 'Hello', 'World' );

Production:

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
la source
5
La première fois que j'ai trouvé debug_backtrace()quelle superbe fonction. J'utiliserai celui-ci!
David Yell
26

Utilisez 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
la source
9
Cela fait définitivement ce que vous voulez. Mais attention, debug_backtrace()c'est un appel coûteux. Ne prenez pas l'habitude de l'utiliser pour déterminer les chaînes d'appels. Si vous souhaitez "protéger" ces fonctions, consultez la POO et les méthodes protégées.
ircmaxell
18

La solution la plus rapide et la plus simple que j'ai trouvée

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] => ->
        )

)

Je teste la vitesse sur un ordinateur portable Lenovo: processeur Intel Pentiom N3530 2,16 GHz, RAM 8 Go

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

Résultats:

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
la source
Pour moi, DEBUG_BACKTRACE_IGNORE_ARGS a été très utile, sans lui, il y avait beaucoup trop d'informations.
Arie
15

Donc, si vous ne savez toujours VRAIMENT pas comment, voici la solution:

$backtrace = debug_backtrace();
echo 'Mu name is '.$backtrace[1]['function'].', and I have called him! Muahahah!';
Marverix
la source
1
Vous pouvez donc utiliser if ($ backtrace [1] ['function'] == 'epic') {// faire des trucs; sinon faites d'autres choses; } ?? wow
Buttle Butkus
2
Oui, mais non! Pas dans le code d'application permanent, de toute façon. Utilisez des paramètres. debug_backtrace () ressemble à une opération assez lourde.
Kluny
3

Essayez ci-dessous le code.

foreach(debug_backtrace() as $t) {              
   echo $t['file'] . ' line ' . $t['line'] . ' calls ' . $t['function'] . "()<br/>";
}
Makwana Ketan
la source
Bonne solution directe pour récupérer la trace de tous les fichiers à partir desquels une fonction particulière est appelée.
Exception
3

Si vous souhaitez tracer l'origine exacte de l'appel en haut de la pile, vous pouvez utiliser le code suivant:

$call_origin = end(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));

Cela ignorera les fonctions enchaînées et n'obtiendra que les informations d'appel les plus pertinentes (pertinentes est utilisée vaguement car cela dépend de ce que vous essayez d'accomplir).

Phillip Weber
la source
Je vous remercie. qui m'a fait gagner beaucoup de temps :)
Mohamed hesham
-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");

J'espère que ça aide quelqu'un. Si la fonction réelle est en dehors de httpdocs, elle ne peut pas être trouvée car le serveur sera configuré pour ne pas l'autoriser. Il n'a été testé que dans un seul dossier, mais la méthodologie récursive devrait fonctionner en théorie.

C'est comme la version 0.1 mais je n'ai pas l'intention de continuer le développement, donc si quelqu'un le met à jour, n'hésitez pas à le republier.

Extraterrestre
la source
Trop de travail: ajoutez ceci à .bashrc function ff() { grep "function $1" $(find ./ -name "*.php") } puis appelez ff failou ff epic. voir: github.com/MaerF0x0/VimSetup/blob/master/bashrc#L122
Mike Graf