Is there a way to list all functions used by php call?
For example let's assume that I have a page called example.com/page_to_test.php and this page uses multiple functions within the page itself or from other classes.
What I want is a list of all functions used during the call (at runtime).
You could register a tick function to achieve this
declare(ticks = 1);
$calls = array();
function tracer() {
global $calls;
$bt = debug_backtrace();
if (count($bt) <= 1) return;
$function = $bt[1];
$call = $function['function'];
if (isset($function['class'])) {
$call = $function['class'] . '::' . $call;
}
$calls[$call] = true;
}
register_tick_function('tracer');
After execution of your script, $calls contains each called function in it's keys.
But just do this for debug purpose, as it's very slow.
What can help you is the PHP function
debug_backtrace()
Read more about it at:
http://php.net/manual/en/function.debug-backtrace.php
Related
I'm tryin to document a my PHP library with doxygen, but I cannot configure it to let recognize the correct usage of member function of my class, using the keyword "self". For instance the following code:
Class myclass{
public static function myfunc1(){
return 10; }
public static function myfunc2(){
return self::myfunc1(); }
}
is not correctly documented. Doxygen maps the two funcions, but when it refer to the internal or external call to these function, it doesn't take in account the myfunc1 called by myfunc2.
My workaround at the moment is to changed the code as follows:
Class myclass{
public static function myfunc1(){
return 10; }
public static function myfunc2(){
return myclass::myfunc1(); }
}
In this case doxygen refers correctly to the usage of myfunc1 related to myfunc2. Of course I don't like very much this solution. How can I solve this issue?
thank you very much
Doxygen provides input filter option, which enables us to change the source code at the time of documentation creation. For e.g. It gives us ability to intercept the code and change the code self::myfunc1 to myclass::myfunc1 on fly, which Doxygen understands. It does not change the actual source code in any way.
I have created a filter based on code from Doxygen PHP Filters with some modifications, which can do the changes for you.
Please create a file /path/to/selfFilter.php and put the code inside it:
<?php
//Create file /path/to/selfFilter.php
$source = file_get_contents($argv[1]);
$tokens = token_get_all($source);
$classes = array();
foreach($tokens as $key => $token)
{
if($token[0] == T_CLASS)
$classes[] = $tokens[$key+2][1];
}
if(!empty($classes))
{
list($source, $tail) = explode('class ' . $classes[0], $source, 2);
$class_code = '';
for($i = 1; $i < count($classes); $i++)
{
list($class_code, $tail) = explode('class ' . $classes[$i], $tail, 2);
$class_code = preg_replace('#\bself::#', $classes[$i-1].'::', $class_code);
$source .= 'class ' . $classes[$i-1] . $class_code;
}
$class_code = preg_replace('#\bself::#', $classes[count($classes)-1].'::', $tail);
$source .= 'class ' . $classes[count($classes)-1] . $class_code;
}
echo $source;
Update the following options in your doxygen config file.
INPUT_FILTER = "php /path/to/selfFilter.php"
FILTER_PATTERNS =
FILTER_SOURCE_FILES = YES
FILTER_SOURCE_PATTERNS =
Please make sure that the /path/to/selfFilter.php is executable and php is available on the path, otherwise use the full php path
INPUT_FILTER = /usr/bin/php /path/to/selfFilter.php
If you run the Doxygen now it should work. Please let me know if you have any issues.
Note: The keyword 'class' should be defined in lower case for the above filters to work.
Can non-anonymous functions in PHP using 'use' keyword? Or it is available for anonymous functions only.
Can I write a php file like this
// L.php
// assume $_texts is in this context..
$_language = null;
function L_init($language) use (&$_language)
{
$_language = $language;
}
function L($key) use ($_texts, $_language)
{
$_texts[$_language][$key];
}
So, another file can use it like this
// client.php
require_once 'L.php';
L_init('en');
echo L('GREETING'); // Will output localize string of key 'GREETING'
It is available for anonymous functions, but you can assign it to a variable:
$some_external_var = "World!";
$function = function() use($some_external_var){
echo "Hello ".$some_external_var;
};
Finally you can invoke it with:
call_user_func($function);
or just:
$function();
No you can't.
The code generate syntax errors.
I'm trying to make a little benchmarking script where I can enter short pieces of code for quick evaluation of my anticipations. I imagine it similar to jsPerf (but password-protected for security reasons).
The main loop should look like this:
public function run(&$t, $count) {
//Run setup function
if(is_callable($this->setup))
call_user_func($this->setup);
//Save inital time
$t($this->name);
//THE MAIN LOOP
for($i=0; $i<$count; $i++) {
call_user_func($this->fn);
}
//Save end time
$t($this->name."_end");
//return time difference
return $t[$this->name."-".$this->name."_end"];
}
However, this will only work with static approach - with functions defined while making the script:
//New instance of tester
$b = new Benchmarker();
$b->add(
//Name
"touch",
//closure
function() {
touch("file.txt");
},
//Code seen in final reports
"touch()"
);
So as you see, I use call_user_func, not eval. Besides the fact that it's evil function in it's nature, I want to avoid it for performance reasons. If I'm testing a code that takes about 10ns to process and eviluation takes about 100ns, my results will be rather random.
This is why I'm looking for a way to convert string to a callable object. You can think about it like one-time eval.
$callable = string_to_callable("function() {echo \"Hello world!\";}");
$b->add(
//Name
"echo",
//callable object
$callable,
//Code seen in final reports
"echo \"...\""
);
Is that possible?
Note:
I can see funny workaround using include:
//Code received from the user
$code = "echo \"Hello world!\";";
//Random name for a new function
$rndname = "fn_".rand(0,100000); //There are smarter ways to do this of course
//String of the new function
$func = "function $rndname() {{$code}}";
//Define a filename
$f = $rndname.".php";
//Put the code in the file
file_put_contents($f, "<?php\n$func\n?".">");
//Include the new script
include $f;
//Call the function
call_user_func($rndname);
//Delete the file
unlink($f);
I really do hope that I won't need the code above!
Apart from creating a new file, there may be a closure trick:
function string_to_callable($string) {
return eval("return function() {{$string}};");
}
Take a look at the following illustration:
// Trims input, fixes spaces and encodes bad glyphs. Also works with arrays.
function prepare_param($param)
{
$retval = "";
function prc($param)
{
$r = split(" ", trim($param));
foreach($r as $i => $e)
$r[$i] = urlencode($e);
return join("+", $r);
}
// If input is an array
if(is_array($param))
{
$retval = array();
foreach($param as $e)
$retval[] = prc($e);
}
// If input is a string
else if(is_string($param))
{
return prc($param);
}
else throw new Exception("Invalid input! Expected String or Array.");
}
Obviously the function prc will now be declared globally, even though declared inside a function. Is there a way to follow this principle, creating a tiny function/macro inside another function as not to litter the global scope? The alternative would be to make a class with a private function, which seems like overkill for my use.
Any help appreciated
You probably want closures, which are anonymous functions.
If you have PHP 5.3, enter anonymous functions:
$prc = function($param)
{
$r = split(" ", trim($param));
foreach($r as $i => $e)
$r[$i] = urlencode($e);
return join("+", $r);
};
if(is_array($param))
{
$retval = array();
foreach($param as $e)
$retval[] = $prc($e);
}
else if(is_string($param))
{
return $prc($param);
}
In this case, $prc only lives in the scope of your prepare_param() function.
If you have access to >=PHP 5.3, you can use anonymous functions, and if not, you can use create_function.
If you don't have PHP 5.3, you can use the create_function function.
There are two ways to do so. The closures/anonymous functions are possible from PHP 5.3, and the oldschool way would be to use create_function() - which is quite fugly.
However in your case, you don't want either. There is no benefit in creating or recreating the function. You just need it once, as it does not depend on any initialization state. The idiom you should use is called "dererred definition" and possible in PHP with:
if (!function_exists("prc")) {
function prc($param) {
...
}
}
You should name it with its parent function as prefix however (e.g. prepare__prc) to avoid clashes and to signalize its internal use.
Oh, and btw it could also be simplified compacted into:
$param = join("+", array_map("urlencode", split(" ", trim($param))));
anonymous functions might be what you are looking for
<?php
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
If you don't use php 5.3 please be aware of the fact that the memory allocated by the "create_function()" function isn't released until the php process finishes. So if you create a lot of functions you might be running into issues.
I am trying to assign a variable to a class in PHP, however I am not getting any results?
Can anyone offer any assistance? The code is provided below. I am trying to echo the URL as shown below, by first assigning it to a class variable.
class PageClass {
var $absolute_path = NULL;
function get_absolute_path(){
$url = $this->absolute_path;
echo $url;
}
}
$page = new PageClass();
$page->absolute_path = "http://localhost:8888/smile2/organic/";
$page->get_absolute_path(); //this should echo the URL as defined above - but does not
It also works for me.
Take a look at a live example of your code here.
However, there are a few things you should change about your class.
First, Garvey does make a good point that you should not be using var. That's the older PHP4, less OOP conscious version. Rather declare each variable public or private. In fact, you should declare each function public or private too.
Generally, most classes have private variables, since you usually only want to change the variables in specific ways. To achieve this control you usually set several public methods to allow client functions to interact with your class only in restricted predetermined ways.
If you have a getter, you'd probably want a setter, since these are usually used with private variables, like I described above.
A final note is that functions named get usually return a value. If you want to display a value, it is customary to use a name like display_path or show_path:
<?php
class PageClass
{
private $absolute_path = NULL;
public function set_absolute_path($path)
{
$this->absolute_path = $path;
}
public function display_absolute_path()
{
echo $this->absolute_path;
}
}
$page = new PageClass();
$page->set_absolute_path("http://localhost:8888/smile2/organic/");
$page->display_absolute_path();
// The above outputs: http://localhost:8888/smile2/organic/
// Your variable is now safe from meddling.
// This:
// echo $this->absolute_path;
// Will not work. It will create an error like:
// Fatal error: Cannot access private property PageClass::$absolute_path on ...
?>
Live Example Here
There's a section on classes and objects in the online PHP reference.
class PageClass {
public $absolute_path = NULL;
function get_absolute_path(){
$url = $this->absolute_path;
return $url;
}
}
$page = new PageClass();
$page->absolute_path = "http://localhost:8888/smile2/organic/";
echo $page->get_absolute_path();
Works fine for me.
Have you checked that the script and esp. the code in question is executed at all?
E.g. add some unconditional debug-output to the script. Or install a debugger like XDebug to step through the code and inspect variables.
<?php
class PageClass {
var $absolute_path = NULL; // old php4 declaration, see http://docs.php.net/oop5
function get_absolute_path() { // again old php4 declaration
$url = $this->absolute_path;
echo "debug: "; var_dump($url);
echo $url;
}
}
$page = new PageClass();
$page->absolute_path = "http://localhost:8888/smile2/organic/";
echo "debug: page->get_absolute_path\n";
$page->get_absolute_path();