Original address: http://www.cnblogs.com/melonblog/archive/2013/05/09/3062303.html
Original soy milk fritters-melon
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 (); function one () {one () ;} function () { three ();} function three () { print_r (Debug_backtrace ());} /* Output: Array ( [0] = = Array ( [file] + D:\apmserv\www\htdocs\test\debug\index.php [line] = = [ 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.
Come back to see debug_backtrace, from the name to see the use is very clear, 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 the Magic function get 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 value echo getfuncname ();p rintfuncname (); Object::p rintmethodname ();//After calling the above two functions, Again in the external output getfuncname, see if there is a ' cache ' such as a problem echo getfuncname (); function Printfuncname () {echo getfuncname ();} Class Object {static function printmethodname () {echo getfuncname (); }}/** * Gets 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 */function getfuncname ( ) {$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 previous (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 load the _inc in package.php using the same method. _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 * * @param string $path relative file path */function import ($path) { //Get backstrace list $debug _backtrace = Debug_backtrace (); The first backstrace is the source script that calls import $source = $debug _backtrace[0]; Get the directory path of the calling source, combined with the file path, you can calculate the full path $source _dir = dirname ($source [' file ']); Require Realpath ($source _dir. ‘/‘ . $path);}? >
package.php:
<?phpecho ' package '; import ('./_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 directory define (' App_path ', DirName (__file__)); Import (App_path. '/package/package.php ');//Output packet information package_printinfo ();/** * Load files under current project * * @param string $path file path */function Import ($path) { //should check the legitimacy of the path $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 _package_printstr ($string) { echo $string;}? >
package.php:
<?phpdefine (' Package_path ', DirName (__file__));//import of private files (package_path. '/_inc_func.php '); function Package_printinfo () { _package_printstr (' I am a package. ‘ );}? >
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 '); _package_printstr (' I loaded the/package/_inc_func.php script ');//output://I 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 function in index.php , the complete code is as follows:
/** * Load files under current project * * @param string $path file path */function import ($path) {//first check the legitimacy of the path $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 the 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 the source script that calls import $source = $debug _backtrace[0]; Get the call source path, use it to compare with 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, ', $s ource[' 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_r (Debug_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 '), function Import () { $debug _backtrace = Debug_backtrace (); $backtrace = $debug _backtrace[0]; if (!isset ($backtrace [' file '])) { //Use the Reflection API to get the number of files and rows declared by the function $reflection _function = new Reflectionfunction ($ 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.php [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.
Use PHP's debug_backtrace function to implement PHP file Rights Management, dynamic Load "reflection"