{php} php quick profiler

Posted by punzalan at 2020-02-27

Original: PHP quick profiler by Ryan Campbell

Vayn a.k.a. VT < vayn at (not spam) vayn dot de >

In our company, code audit is an integral part of the development process of making high-quality software. When we developed wuhoo, we chose mentor style approach, that is, a developer works in a part for a period of time, and then passes this part to a more experienced developer for audit. We love this approach because it means more developers are getting familiar with the basics of different code layer services. More importantly, they play the role of extra protection against security vulnerabilities, memory leaks, poor queries, and complex file structures. Unfortunately, these audits are also time consuming and sometimes inconvenient for auditors in a small team - they also have their own todo list to complete.

Code auditing conflicts with the same development requirements on worksheets. We find that we repeat the same tasks again and again. We spend a lot of time exporting queries, memory statistics, and objects to browsers just to see how they are used in code. To reduce this duplication, we spent some time to create a tool called PHP quick profiler, or PQP for short. This is a small tool (imagine firebug for PHP) that can analyze and debug for developers based on relevant information without adding a lot of programming overhead to their code. Now, we only need to toggle one config setting to true and our viewers have access to an automated tool to help create a fast and more consistent review experience. Since anyone can use it, PQP also gives the initial developer an idea of where their code standards are before the review.

We have been using PQP on Wufoo project for some time. It's very useful, so we decided to take the time to package everything, write some documents, and then make the PQP available to everyone.

See how PQP works

We have made an online example to show an arrival page with PQP enabled. The analyzer consists of five tabs: logging messages, measuring execution time, analyzing queries, requesting memory used and showing the files included.

Thanks to Kevin's help, he has done a great job - designing and compressing the interface so that external CSS and scripts are not added to make the PQP display well. PQP can run on Internet Explorer 6 and later, as well as Firefox and safari.

Start using

We provide a zip document containing all the installation files and basic installation instructions of PQP.


You download the zip package, unzip it, and upload all the files to a PHP enabled web server. Using a browser to access the directory where the files are located, you will see the same example as the online example above. You will see that all the tags except the database tags work well, and the database tags need some extra settings.

When you are sure the sample will work, the next step is to integrate it with your own project. Note: putting the PQP folder directly into your project directory does not work. This is because the code in the demonstration has five different aspects, and you may need to deal with these situations in a different way than we do. That is to say, integration is very simple. You just need to follow each of the following instructions to set up and run PQP immediately.

Use PQP in your code

The easiest way to make PQP work is to include the phpqquickprofiler.php file in the code you want to display PQP. This includes the console, memory logging, and file logging separately. Additional settings are required for database and speed recording, which we'll explain later. Now, the default record works well, but the inclusion only file does not display the information on the screen. To display information on the screen, you need some knowledge of what happens when you include files.

When the code is executed, the running details will be recorded and analyzed by PQP. When the code is executed, PQP also works and the output is displayed on the screen. The tricky part is that you need to know when the code ends, and ideally the tool should work with as few changes as possible from the developer. In this case, the way we judge the end of the code is to see when the parent's destructor runs. So the schedule would be this:

Of course, this installation will keep the PQP displaying output, which is not ideal for the product. To make it more useful, we added a configuration ID (debugmode = true) to our code and checked whether it was set to true before displaying it. The following sample class performs the steps we just mentioned:

class ExampleLandingPage {
private $profiler;
private $db;

public function __construct() {
    $this-&gt;profiler = new PhpQuickProfiler(PhpQuickProfiler::getMicroTime());

public function __destruct() {
    if($debugMode == true) $this-&gt;profiler-&gt;display($this-&gt;db);
private $profiler; private $db; public function __construct() { $this-&gt;profiler = new PhpQuickProfiler(PhpQuickProfiler::getMicroTime()); } public function __destruct() { if($debugMode == true) $this-&gt;profiler-&gt;display($this-&gt;db); }



logging to console

Through the above code, PQP has been set up and is ready for use. We can start by referencing the help function, starting with the record. The console record goes further than the echo declaration, compressing and formatting the output using print_r. This is good for auditors because it provides a way to display debugging information without breaking the layout of the page. To output data to the console, you only need to call the function statically:

echo print_r Console::log($data);

Static function calls accept any data type, as long as the phpqquickprofiler.php class is included. We choose to implement it in a static way so that the class does not have to be instantiated before use. The following static call is to store the record history into a PHP global variable. If you don't want to use global variables, instantiate the console. PHP class so that it saves the record as a member variable. But like this, this class just acts as a wrapper for global PHP variables.

On top of the logging variables, the console has four additional functions.

Console::logError($exception); Console::logMemory(); Console::logMemory($variable, $name); Console::logSpeed();

Let's start with logerror(). Logging an error is useful for displaying information about PHP exceptions. In our code, we will use a catch block to handle errors, which can make exceptions silent. We do this because we want to ignore the error so that it doesn't affect what the user does. Now, it's better to understand the thrown exception in the development, so calling logerror() in the catch block can make the information displayed in the console as follows:

try { // Execute non critical code } catch(Exception $e) { Console::logError($e, 'Unable to execute non critical code'); }

In addition, the console can provide more values by using PHP's built-in help functions. For example, logging debug UU backtrace() will print information about the point in time specified by the script. PHP provides magic constants such as \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\. Take a look at the screenshot below, which contains some examples of usage:


Observe memory usage

Object oriented PHP is a beautiful thing to look at, but there are several clear issues to keep in mind when it comes to memory usage. These problems can easily cause some situations when dealing with recursive output (for example, output to excel), if there is memory leak when creating objects or the objects are not properly destroyed. All of these will lead to unexpected resource use and fatal errors, aggravating the deterioration of end-user use.

Use a debugger with memory management assistance to display the maximum amount of memory available for a script. Memory? Get? Peak? Usage() has a simple call built in at the beginning of the data. System settings for memory usage (via ini? Get()) are also displayed to see how much room is left. If the overview is not enough, you can drill down into your resource usage with a point in time memory call.

memory_get_peak_usage() ini_get() Console::logMemory(); Console::logMemory($variable, $name);

Calling logmemory() in your code without any parameters will output the current memory usage of PHP when a function is called. It's a perfect way to look at the loops in your code, and it's a way to look at the memory growth in each iteration. Again, a variable and a name can be passed to this function. This will output the memory usage of variables in the console. It's amazing to know that a script is taking up memory. Knowing which variable is taking up memory can fix the problem. Take a look at the screenshot below, which shows that string concatenation is slowly consuming memory.

Out of control inclusion

Like memory runaway, including files (especially in large projects) can proliferate very quickly before taking over your app. To make matters worse, too many include system errors caused by memory usage that will not be thrown. Instead, the page slows down and resources are consumed each time a request is processed. It's easy to avoid this trap - just make sure that the same file isn't included multiple times, and catch any unnecessary over inclusion of files.

The document label of PQP shows the total content and size of all files by calling get included files. The names and sizes of individual files are also output to the console for easy viewing. The largest include file is marked on the left, which clearly indicates whether a large library file in use should not be used. For example, on the Wufoo project, we found that there is a script that always contains htmlawed, a fairly decent sized file that it doesn't need.


Also, keep in mind that autoloading classes or using require once can usually alleviate any problems caused by file inclusion. That is to say, it never hurts to be aware of the situation, especially when you are using plug-ins, old code, or borrowed code.


Page execution time

We always emphasize on database optimization when it comes to performance considerations (right fully so), but this does not mean that PHP execution time is ignored. The standard way to calculate the page load time is to find the time difference between the start and end of the script. This makes integrating debuggers into your own projects tricky. When the debugger is called on the destruction of the parent page, we know when the script ends. But because each project is different, the start time can be varied. The sample code you download sets the start time by calling getmicrotime () of PQP with the constructor of the parent object. This method works in most cases, but if you have a bunch of code running before the parent object is constructed, be sure to set the start time explicitly when you need it.

getMicroTime() $this->profiler = new PhpQuickProfiler(PhpQuickProfiler::getMicroTime());

Given the execution time of the page, the next step will be to find out the meaning of the information. Take a quick look to see if the time is within the acceptable range. If not, how can we debug and solve this problem? Using the query part of the debugger, we can exclude the query execution time (explained in detail in the next section). If the query is not a problem, then some part of the script must be. We find the problem through the console.


The call to logspeed () tells us how long it took the script to execute to the specified point in time. For example, imagine that we have a factory class that constructs complex objects from a database. We also have an object engine that returns object names from the database. To display 100 object names on the screen, we can use the factory or engine. However, using the engine will be faster, because we only need the name, not the logical processing of object creation. If the developer uses the factory, logspeed () will reveal the slowdown during the display cycle, and finally identify the problem.

logSpeed() logSpeed()

Here's a similar note. We recently found that Xcache improved our page execution time by about 60%. This conclusion has been benchmarked and all of our developers have used PQP to test the code quickly.

List of database activities

Getting the debugger to report database information is the hardest part of integrating PQP into your own project. The next steps will not work unless your database has some way of abstract interaction. We talked about a simple database class awhile back not long ago, and released a zip Download with examples (MySQL database.php - you can see a complete implementation according to the code). This class allows the queries to each go through the same analysis without additional work by the programmer.

When a query is called, the database wrapper class stores the query and records the time. The simplified code looks like this:

function query($sql) { $start = $this->getTime(); $rs = mysql_query($sql, $this->conn); $this->logQuery($sql, $start); return $rs; }

function logQuery($sql, $start) { $query = array( 'sql' => $sql, 'time' => ($this->getTime() - $start)*1000 ); array_push($this->queries, $query);}

function logQuery($sql, $start) { $query = array( 'sql' => $sql, 'time' => ($this->getTime() - $start)*1000 ); array_push($this->queries, $query); }

Using this concept, this class places all valid query information in an array. The debugger can then use arrays to print out information. What is printed out is the latest stored query information itself and the execution time. The execution time is not precise - it's until PHP processes the Recordset, which is a little slower than the query time if there's a network delay in connecting to the database. To see if queries affect more records than planned, such as databases being replicated or open to SQL injection, browsing query time is a simple and useful way,

One of the most useful database features added to the debugger is the ability of the debugger to interpret each query run. Each query is run again with an explanation statement, and the results are displayed below the query. This makes it easy to determine whether queries use their indexes properly.

Concluding remarks

The ultimate goal of this debugging tool is to present a summary of useful information in an automated format. Basically, finding out about certain aspects of the code would require manual work and thought. Then if you run into a problem, the debugger wants to make it easier to narrow it down by using those extended console functions. With that in mind, this tool is just an aid and is in no way mean to replace the standard, those procedures available to developers. We encourage developers to use slow query log, PHP error log and full fledged debuggers and profilers are enriched on top of this high level view to supplement the tools available to developers.


Translator: the translation is not so good consciously, but it basically conveys the meaning of the original. If there is any problem with the translation, please understand it and be elegant.