PHP Debug_backtrace's cranky, phpdebugbacktrace_php tutorial

Source: Internet
Author: User

PHP Debug_backtrace's cranky, phpdebugbacktrace


The sample code test environment for this article is Apmserv (PHP5.2.6) under Windows

Briefly

As you may all know, PHP has a function called debug_backtrace, which can be traced back to the function of the call information, can be said to be a debugging tool.

OK, let's review it.

One ();functionOne () {one ()};functionBoth () {three ();}functionthree () {Print_r(Debug_backtrace() );}/*output: Array ([0] = = Array ([file] = D:\apmserv\www\htdocs\test\debug\index.php [l    INE] = [function] = three [args] = Array ())            [1] = = Array ([file] = D:\apmserv\www\htdocs\test\debug\index.php [line] = 6        [function] = both [args] = array ()) [2] = = Array ([File] = D:\apmserv\www\htdocs\test\debug\index.php [Line] = 3 [function ] = = one [args] = Array ()))*/

By the way, a similar function:debug_print_backtrace, the difference is that it will print the backtracking information directly.

back to see Debug_backtrace , the use of the name is very clear, it is for developers to debug. Until one day I noticed it returns the file parameter,file representing the source of the call script for the function or method (in which script file is used). Suddenly I thought, if the current script knows the source of the call, whether it can be based on this source of different, to achieve some interesting features, such as file Rights Management, dynamic loading and so on.

Actual combat

Implement Magic Functions

Gets the name of the current function or method

Although the __function__ and __method__ Magic constants are already in PHP, I would like to introduce a way to get the current function or method name using debug_backtrace .

The code is as follows:

//function External output getfuncname valueEchogetfuncname ();p rintfuncname ();Object::printmethodname ();//after calling the above two functions, getfuncname the external output again to see if there is a ' cache ' problemEchogetfuncname ();functionPrintfuncname () {Echogetfuncname ();}class Object {    Static functionPrintmethodname () {EchoGetFuncName (); }}/** * Get the name of the current function or method * function is called getfuncname, OK, actually method can also as function, can't think of a good name * * @return String name*/functionGetFuncName () {$debug _backtrace=Debug_backtrace(); //If the function name is one of the following, indicating that the script was loaded and called outside the function GetFuncName//This case should return an empty    $ignore=Array(        ' Include ', ' include_once ', ' require ', ' require_once '    ); //The first backtrace is the current function getfuncname, and then the last (second) BackTrace is the function that calls GetFuncName .    $handle _func=$debug _backtrace[1]; if(isset($handle _func[' function ']) &&!In_array($handle _func[' function '],$ignore ) ) {        return $handle _func[' function ']; }    return NULL;}//Output://null//printfuncname//printmethodname//null

It seems to be no problem, very good.

Loading relative path files

If you are loading a file of relative paths in your project, you must use native methods such as include or require , but now you have debug_backtrace, I can use a custom function to load a relative path file.

Create a new project with the following directory structure:

I want to invoke the custom function in index.php and use the relative path to load the package/package.php, and use the same method in package.php to load the _inc_func.php

The code for the three files is as follows (note the code for index.php and package.php calling the import function):

index.php:

 
  Phpimport ('./package/package.php ' ); /* * * Load files under current project *   */ function $path ) {    // get backstrace list    $debug _backtracedebug_backtrace ();     // The first backstrace is a source script    that calls import $source $debug _backtrace [0];     // get the directory path of the calling source, combined with the file path, to calculate the full path    $source _dir dirname $source [' file ']);     require Realpath $source _dir $path  );}? >

package.php:

 
  PHPecho 'package './_inc_func.php ' );? >

_inc_func.php:

 
  PHPecho ' _inc_func ';? >

Run index.php:

// Output://package//_inc_func

As you can see, I have succeeded.

Think: This method I feel very strong, in addition to the relative path, can be based on this idea to extend the relative package, relative modules and other abstract features, for some projects can enhance the role of modularity.

Manage File invocation Permissions

I agreed to a specification: The file name is underlined before it can only be called by the current directory of files, that is, the file belongs to the current directory ' private ', other directory files are not allowed to load them.

The purpose of this is clear: to reduce the coupling of code. Many times in a project, some files are used only in specific scripts. But what happens most often is that some programmers find that these scripts have functions or classes that they need to use, and therefore load them directly to achieve their goals. This is not good, originally the purpose of these scripts are only to assist some interface implementation, they do not take into account the other commonality. In case of refactoring within the interface, these specific script files need to be changed, but some seemingly unrelated scripts will suddenly fail to run. Once checked, it is found that the file references are intricate.

The norm is only the supervisory function, does not rule out someone to violate this norm for one's own selfish desire, or inadvertently violates. The best way to do this is to put it into your code and let the program automatically detect the situation.

Create a new project with the following directory structure.

So for this project,_inc_func.php belongs to The package directory's private file, only package.php can load it, and index.php It does not have this permission.

The package directory is a package,package.php provides the interface for this packet, while _inc_func.php has some functions that package.php need to use. index.php will use this package's interface file, which is package.php

Their code is as follows

index.php:

 PhpHeader("content-type:text/html; Charset=utf-8 ");//define the project root directoryDefine(' App_path ',dirname(__file__); Import (App_path. '/package/package.php ' );//information about the output packagepackage_printinfo ();/** * load files under current project * * @param string $path file path*/functionImport$path ) {        //the legitimacy of the path should be checked    $real _path=Realpath($path ); $in _app= (Stripos($real _path, app_path) = = 0 ); if(Empty($real _path) || !$in _app ) {        Throw New Exception(' File path does not exist or is not allowed ' ); }        include $real _path;}?>

_inc_func.php:

 
  PHPfunction$string  ) {    echo$string;}? >

package.php:

 
  PHPdefinedirname__file__  )); // introduce a private file import (Package_path. '/_inc_func.php ' ); function Package_printinfo () {    ' I am a bag. ' );}? >

Run index.php:

// output://I am a bag. 

The entire project uses the import function to load the file, and the code looks normal. But I can load the package/_inc_func.php file in index.php and invoke its method.

Change import (App_path. index.php) in the '/package/package.php '); Code, and run:

Import (App_path. '/package/_inc_func.php' I loaded the/package/_inc_func.php script ' ); // output://I have loaded the/package/_inc_func.php script

Then, you can use debug_backtrace to check where the path to the loaded _inc_func.php file came from, and I changed the import in index.php function, the complete code is as follows:

/** * load files under current project * * @param string $path file path*/functionImport$path ) {        //the legitimacy of the path should be checked first    $real _path=Realpath($path ); $in _app= (Stripos($real _path, app_path) = = 0 ); if(Empty($real _path) || !$in _app ) {        Throw New Exception(' File path does not exist or is not allowed ' ); }        $path _info=PathInfo($real _path ); //determine if a file belongs to a private    $is _private= (substr($path _info[' basename '], 0, 1) = = = ' _ ' ); if($is _private ) {        //Get backstrace list        $debug _backtrace=Debug_backtrace(); //The first backstrace is a source script that calls import        $source=$debug _backtrace[0]; //get the call source path and use it to compare to the target path        $source _dir=dirname($source[' File '] ); $target _dir=$path _info[' DirName ']; //throws an exception when not in the same directory        if($source _dir!==$target _dir ) {            $relative _source_file=Str_replace(App_path, ",$source[' File '] ); $relative _target_file=Str_replace(App_path, ",$real _path ); $error=$relative _target_file. ' File belongs to private file, '.$relative _source_file. ' Cannot load it. '; Throw New Exception($error ); }    }        include $real _path;}

Running index.phpagain will result in a fatal error:

// output://Fatal error: The/package/_inc_func.php file belongs to a private file and/index.php cannot be loaded into it. 

Loading package.php is not a problem, and there is no demo.

As you can see, I succeeded in my original idea. Even so, after loading package.php , it is still possible to call _inc_func.php 's function in index.php (package.php loaded it). Because in addition to anonymous functions, other functions are globally visible, including classes. However, this will make the programmer more or less alert. The key is to look at the programmer itself, and good standards and constraints can not resist the bad programmers, they will always be smarter than you.

Debug_backtrace's ' BUG '

If you use call_user_func or Call_user_func_array to invoke other functions, the function they call uses debug_backtrace, Will not get the information for the path.

Cases:

Call_user_func (' Import '); function import () {    print_rdebug_backtrace());} /* output: Array (    [0] = = Array        (            [function] = import            [args] = array                (                )        )    [1] = = Array        (            [File] = F:\www\test\test\index.php            [line] = 3            [function]            = = Call_user_func [args] = > Array                (                    [0] = import                )        )* /

Note that the first backtraceof the output, its call source path file is not there, so my previous examples will cause problems. Of course you may notice the second backtrace, if the first one does not go back. But after practice is not feasible, I have encountered this situation, the same problem, but now can not retrieve the code at that time, if you find, please tell me the question. For the time being, it is best not to use this approach, I have a better solution, is to use the PHP reflection API.

Using reflection

You can use the reflection API to know the details of a function, including the file it declares and the number of rows it is in.

Call_user_func(' Import ');functionimport () {$debug _backtrace=Debug_backtrace(); $backtrace=$debug _backtrace[0]; if( !isset($backtrace[' File '] ) ) {        //use the Reflection API to get the number of files and rows for a function declaration        $reflection _function=NewReflectionfunction ($backtrace[' function '] ); $backtrace[' file '] =$reflection _function-GetFileName (); $backtrace[' line '] =$reflection _function-Getstartline (); }    Print_r($backtrace);}/*output: Array ([function] = import [args] = array () [File] = F:\WWW\TEST\TEST\INDEX.P HP [Line] = 5)*/

You can see thatthefile is back by using the Reflection interface Reflectionmethod method.

The reflection interface of a class method is Reflectionmethod, and the method of getting the declaration is also GetFileName.

Summarize

In a project, I usually don't load scripts directly using include or require . I like to wrap them in a function and call this function when I need to load the script. This can be done in the function of some judgment, such as whether to introduce the file, or add some call rules, etc., maintenance is more convenient.

Fortunately, with this habit, I can immediately apply some of Debug_backtrace 's ideas to the whole project.

Overall Debug_backtrace has a lot of flexibility, and with a little bit of leverage, some interesting features can be achieved. But at the same time I find it is not very well controlled, because every time a method or function is called, it is possible to change its value. If you want to use it to do some logical processing (for example, some of the ideas I've mentioned in this article), you need a system with good rules, at least for loading files.

http://www.bkjia.com/PHPjc/1131136.html www.bkjia.com true http://www.bkjia.com/PHPjc/1131136.html techarticle PHP Debug_backtrace's cranky, phpdebugbacktrace This article sample code test environment is Windows Apmserv (PHP5.2.6) A brief description Maybe everyone knows that PHP has a function called D ...

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.