PHP Archives - Stackify Fri, 17 May 2024 04:36:02 +0000 en-US hourly 1 https://wordpress.org/?v=6.4.4 https://stackify.com/wp-content/uploads/2023/02/favicon.png PHP Archives - Stackify 32 32 PHP Try Catch: Basics & Advanced PHP Exception Handling Tutorial https://stackify.com/php-try-catch-php-exception-tutorial/ Thu, 28 Sep 2023 22:35:03 +0000 https://stackify.com/?p=21724 When PHP version 5 was released, it incorporated a built-in model to catch errors and exceptions. Handling errors in PHP with try catch blocks is almost the same as handling errors in other programming languages.

When a PHP exception is thrown, the PHP runtime looks for a catch statement that can handle that type of exception. It will continue checking the calling methods up the stack trace until a catch statement is found. If one is not found, the exception is handed to the global exception handler that we will also cover in this article.

Exception handling is a mechanism in programming that allows a system to handle unexpected events or errors that occur during the execution of a program

What is Exception Handling?

Exception handling is a mechanism in programming that allows a system to handle unexpected events or errors that occur during the execution of a program. These unexpected events, known as exceptions, can disrupt the normal flow of an application. Exception handling provides a controlled way to respond to these exceptions, allowing the program to either correct the issue or gracefully terminate.

Why Do We Need Exception Handling?

  1. Maintaining Application Flow: Without exception handling, an unexpected error could terminate the program abruptly. Exception handling ensures that the program can continue running or terminate gracefully.
  2. Informative Feedback: When an exception occurs, it provides valuable information about the problem, helping developers to debug and users to understand the issue.
  3. Resource Management: Exception handling can ensure that resources like database connections or open files are closed properly even if an error occurs.
  4. Enhanced Control: It allows developers to specify how the program should respond to specific types of errors.

Exception Handling vs Error Handling

While both error handling and exception handling deal with unexpected situations, they are conceptually different. Error handling typically deals with scenarios that can be anticipated and managed, such as a user entering invalid data. It often involves conditions and checks in the code to handle these situations. On the other hand, exception handling deals with unanticipated errors, like a network outage or a failed database connection. It involves a mechanism to “catch” these exceptions and handle them in a structured way.

Now, let’s move on to revising the content from the provided post.

When PHP version 5 was released, it incorporated a built-in model to catch errors and exceptions. Handling exceptions in PHP using try-catch blocks has become a standard practice, mirroring error handling in many other programming languages.

When a PHP exception is thrown, the PHP runtime system looks for a corresponding catch statement that can handle that specific exception type. It will continue to search through the calling methods up the stack trace until a suitable catch statement is found. If none is discovered, the exception is passed to the global exception handler, which we will delve into later in this article.

Simple PHP try catch example

Here is an example of a basic PHP try catch statement.

try {
    // run your code here
}
catch (exception $e) {
    //code to handle the exception
}
finally {
    //optional code that always runs
}
The try block contains the code that may potentially throw an exception. All of the code within the try block is executed until an exception is potentially thrown

PHP error handling keywords

The following keywords are used for PHP exception handling.

  • Try: The try block contains the code that may potentially throw an exception. All of the code within the try block is executed until an exception is potentially thrown.
  • Throw: The throw keyword is used to signal the occurrence of a PHP exception. The PHP runtime will then try to find a catch statement to handle the exception.
  • Catch: This block of code will be called only if an exception occurs within the try code block. The code within your catch statement must handle the exception that was thrown.
  • Finally: In PHP 5.5, the finally statement is introduced. The finally block may also be specified after or instead of catch blocks. Code within the finally block will always be executed after the try and catch blocks, regardless of whether an exception has been thrown, and before normal execution resumes. This is useful for scenarios like closing a database connection regardless if an exception occurred or not.

PHP try catch with multiple exception types

PHP supports using multiple catch blocks within try catch. This allows us to customize our code based on the type of exception that was thrown. This is useful for customizing how you display an error message to a user, or if you should potentially retry something that failed the first time.

try {
    // run your code here
}
catch (Exception $e) {
    echo $e->getMessage();
}
catch (InvalidArgumentException $e) {
    echo $e->getMessage();
}

When to use try catch-finally

In PHP version 5.5, the finally block was added. Sometimes in your PHP error handling code, you will also want to use a finally section. Finally is useful for more than just exception handling, it is used to perform cleanup code such as closing a file, closing a database connection, etc.

The finally block always executes when the try catch block exits. This ensures that the finally block is executed even if an unexpected exception occurs.

Example for try catch-finally:

try {
    print "this is our try block n";
    throw new Exception();
} catch (Exception $e) {
    print "something went wrong, caught yah! n";
} finally {
    print "this part is always executed n";
}

Below is the diagram showing how the program works.

diagram showing how the finally block is executed

Creating custom PHP exception types

PHP also allows creating custom exception types.This can be useful for creating custom exceptions in your application that you can have special exception handling around.

To create a custom exception handler, we must create a special class with functions that can be called when an exception occurs. The class must be an extension of the exception class.

class DivideByZeroException extends Exception {};

The custom exception class inherits the properties from PHP’s Exception class and you can add custom functions to it. You may not want to display all the details of an exception to the user or you can display a user-friendly message and log the error message internally for monitoring.

The sample below uses a custom PHP exception with multiple catch statements.

class DivideByZeroException extends Exception {};
class DivideByNegativeException extends Exception {};

function process_divide($denominator)
{
    try
    {
        if ($denominator == 0)
        {
            throw new DivideByZeroException();
        }
        else if ($denominator < 0)
        {
            throw new DivideByNegativeException();
        }
        else
        {
            echo 100 / $denominator;
        }
    }
    catch (DivideByZeroException $ex)
    {
        echo "Divide by zero exception!";
    }
    catch (DivideByNegativeException $ex)
    {
        echo "Divide by negative number exception!";
    }
    catch (Exception $x)
    {
        echo "UNKNOWN EXCEPTION!";
    }
}

The code above throws an exception and catches it with a custom exception class. The DivideByZeroException() and DivideByNegativeException() classes are created as extensions of the existing Exception class; this way, it inherits all methods and properties from the Exception class. The “try” block is executed and an exception is thrown if the denominator is zero or negative number. The “catch” block catches the exception and displays the error message.

The flowchart below summarizes how our sample code above works for custom types of exceptions.

The flowchart below summarizes how our sample code above works for custom types of exceptions

Global PHP exception handling

In a perfect world, your code will do proper exception handling. As a best practice, you should also configure a global PHP exception handler. It will be called in case an unhandled exception occurs that was not called in a proper PHP try catch block.

To configure a global PHP exception handler, we will use the set_exception_handler() function to set a user-defined function to handle all uncaught exceptions:

function our_global_exception_handler($exception) {
    //this code should log the exception to disk and an error tracking system
    echo "Exception:" . $exception->getMessage();
}

set_exception_handler(‘our_global_exception_handler’);

How to properly log exceptions in your PHP try catch blocks

Logging is usually the eyes and ears for most developers when it comes to troubleshooting application problems. Logging exceptions so you can find them after they happen is a really important part of PHP error handling best practices.

Try Stackify’s free code profiler, Prefix, to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby, and Python.

Error logs are crucial during development because it allows developers to see warnings, errors, notices, etc. that were logged while the application is running. That you can handle them appropriately through the PHP exception handling techniques try catch we just learned.

Depending on the PHP framework you are using, whether Laravel, Codeigniter, Symfony, or others, they may provide built-in logging frameworks. You can also use Monolog, which is a standard PHP logging library. Regardless of the logging framework you are using, you want to always log important exceptions being thrown in your code.

Here is a sample of a try/catch that logs errors with Monolog:

require_once(DIR.'/vendor/autoload.php');
use MonologLogger;
use MonologHandlerStreamHandler;

$logger = new Logger('channel-name');
$logger->pushHandler(new StreamHandler(DIR.'/app.log', Logger::DEBUG));

try {
    // Code does some stuff
    // debug logging statement
    $logger->info('This is a log! ^_^ ');
}
catch (Exception $ex) {
    $logger->error('Oh no an exception happened! ');
}

How to use try catch with MySQL

The PHP libraries for MySQL, PDO, and mysqli, have different modes for error handling. If you do not have exceptions enabled for those libraries, you can’t use try catch blocks. This makes error handling different and perhaps more complicated.

PDO

In PDO, you must enable ERRMODE_EXCEPTION when creating the connection.

// connect to MySQL
$conn = new PDO('mysql:host=localhost;dbname=stackifydb;charset=utf8mb4', 'username', 'password');
//PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Learn more about PDO attributes from the PHP docs.

MySQL

For mysqli, you must do something similar:

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

Learn more from the My SQL docs.

How to view all PHP exceptions in one place

Proper exception handling in PHP is very important. As part of that, you don’t want to simply log your exceptions to a log file and never know they occurred.

The solution is to use an error-tracking solution like Stackify’s Retrace. All errors are recorded together with some important details about that error, including the time it occurred, the method that caused it, and the exception type.

Retrace provides many important error-tracking and monitoring features. Including the ability to see all except in one place, identify unique errors, quickly find new errors after a deployment, email notifications about new errors, and much more.

Stackify’s error and log management tool can help you easily monitor and troubleshoot your application.

Stackify’s error and log management tool can help you easily monitor and troubleshoot your application

Summary

In this tutorial, we showed how to use PHP try catch blocks. We also covered some advanced uses with multiple exception types and even how to log all of your errors to a logging library. Good error handling best practices are critical to any PHP application. Retrace can help you quickly find and troubleshoot all of the exceptions being thrown in your code.

]]>
Display All PHP Errors: Basic & Advanced Usage https://stackify.com/display-php-errors/ Mon, 24 Jul 2023 08:26:00 +0000 https://stackify.com/?p=21585 A PHP application might produce many different levels of warnings and errors during its execution. Seeing these errors is crucial for developers when troubleshooting a misbehaving application. However, many developers often encounter difficulties displaying errors in their PHP applications, leading to silent app failures.

Understanding the importance of displaying errors in PHP can’t be overstated. Error messages provide vital information about issues that occur while running a PHP script. They inform developers about syntax errors, which are mistakes made while writing code. They also notify developers about missing semicolons, which are important punctuation marks in certain programming languages. Furthermore, they bring attention to more complex issues that need to be debugged. Identifying and fixing these problems becomes a complicated guessing game without visible errors.

With the complexity of PHP web applications, there are multiple methods to display errors, each with advantages depending on your specific use case.

Four different ways to display errors in PHP

Before diving into the details of managing and logging errors in PHP, let’s outline the four main ways to display errors in PHP:

  1. error_reporting: This function allows developers to determine which errors PHP will suggest. It can be set to display all errors, warnings, and notices except for some exceptions like E_NOTICE and E_STRICT.
  2. display_errors: This is a directive in the php.ini file that determines whether errors should be printed to the screen as part of the output or if they should be hidden.
  3. log_errors: This directive tells PHP whether it should log errors. If set to “On”, it will log errors according to what is set in the error_log directive.
  4. error_log string: This directive determines where the error message should be sent. It could be sent to the server’s error log, a TCP port, or a separate file specified in the directive.

If you are having problems with your PHP web application and need to display all the errors and warnings, you are in the right place. In this tutorial, we will explain all the different ways to enable PHP errors and warnings. We will also discuss how to write the errors to a log file and even collect them via the Retrace’s error tracking feature.

Quickly Show All PHP Errors

The quickest way to display all php errors and warnings is to add these lines to your PHP code file:

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
The ini_set function will try to override the configuration found in your PHP ini file

What Do These Lines of Code Do Exactly?

The ini_set function will try to override the configuration found in your PHP ini file.

The display_errors and display_startup_errors are just two of the directives that are available. The display_errors directive will determine if the errors will be displayed or hidden from the user. Usually, the dispay_errors directive should be turned off after development.

The display_startup_errors, however, is a separate directive because the display_errors don’t handle the errors that will be encountered during PHP’s startup sequence. The list of directives that can be overridden by the ini_set function is found in the official documentation.

Unfortunately, these two directives won’t be able to display parse errors such as missing semicolons or missing curly braces. In this case, the PHP ini configuration must be modified.

Configure PHP.ini to display all errors

If adding some of the PHP code errors doesn’t show in the browser during testing, then the PHP ini configuration has some additional directives to handle this.

display_errors = on

The display_errors directive must be set to “on” in the PHP ini file. This will display all the errors including syntax or parse errors that cannot be displayed by just calling the ini_set function in the PHP code. The PHP ini file can be found in the displayed output of phpinfo() function and is labeled loaded configuration file. This directive in the ini configuration must be set to off, if the web application is in production.

Display PHP errors via .htaccess configuration

Developers usually have access to the directory files. The directive for showing PHP errors can also be enabled or disabled using the .htaccess file located in the root or public directory of the project.

php_flag display_startup_errors on
php_flag display_errors on

Similar to what will be added to the PHP code to show PHP errors, .htaccess also has directives for display_startup_errors and display_errors. The advantage of showing or disabling error messages in this manner is that development and production can have different .htaccess files, where the production suppresses the displaying of errors.
Depending on which files you have access to and how you do deployments and server configurations, you may want to configure display_errors in .htaccess or your PHP.ini file. Many hosting providers will not allow you to modify your PHP.ini file to enable display_errors.
In the .htaccess file, a custom error log can also be enabled as long as the log folder or the log file is writable by the web server. The log file can be a relative path to where the .htaccess is located, or it can be an absolute path such as /var/www/html/website/public/logs.

php_value error_log logs/all_errors.log

Enable detailed warnings and notices

Sometimes, the warnings that seem not to affect the application at the start will cause some fatal errors in certain conditions. These warnings must be fixed because this means that the application won’t run normally under certain scenarios. In case these warnings cause a lot of errors, then it would be more practical to hide the errors and just show what the warning messages are.

error_reporting(E_WARNING);

For a developer, showing warnings and hiding errors is just as simple as adding a single line of code. To show warnings and notices, the parameter for the error reporting function will be “E_WARNING | E_NOTICE”. The error_reporting function can accept E_ERROR, E_WARNING, E_PARSE, and E_NOTICE parameters as bitwise operators. To report all errors except for notices, then the parameter is “E_ALL & ~E_NOTICE” where E_ALL stands for all the possible parameters of the error_reporting function.

In-depth with the error_reporting() function

The error reporting function is a built-in PHP function that allows developers to control which and how many errors will be shown in the application. Remember, the PHP ini configuration has an error_reporting directive that will be set by this function during runtime.

error_reporting(0);

To remove all errors, warnings, parse messages, and notices, the parameter that should be passed to the error_reporting function is zero. It would be not practical to have this line of code in each of the PHP files. It would be better to turn off report messages in the PHP ini file or in the .htaccess.

error_reporting(E_NOTICE);

PHP allows variables to be used even when not declared. This is not a standard practice because undeclared variables will cause issues for the application once it is used in loops and conditions. Sometimes, this also happens because the declared variable has a different spelling than the variable being used for conditions or loops. When E_NOTICE is passed in the error_reporting function, then these undeclared variables will be displayed in the web application.

error_reporting(E_ALL & ~E_NOTICE);

The error reporting function allows you to filter which errors can be shown. The “~” character means “not” or “no” so the parameter ~E_NOTICE means not to show notices. Notice the “&” and “|” characters in between the possible parameters. The “&” character is for “true for all”, while the “|” character represents either one as long as it is true. These two characters have the same meaning in PHP conditions OR and AND.

error_reporting(E_ALL);
error_reporting(-1);
ini_set('error_reporting', E_ALL);

These three lines of codes do exactly the same thing, it will show all PHP errors. The error_reporting(E_ALL) is the most widely used among developers to show error messages because it is more readable and understandable.

Log PHP errors to a file using the error_log() function

During production, error messages must not be shown to the end users, but this information must still be recorded for tracing purposes. The best way to record these error messages on a production web application is to store it in log files.
One easy way to use log files is to use the error_log function, which accepts four parameters. The only required parameter is the first parameter, which contains the details about the error or what’s to be logged. The type, destination, and header are all optional parameters for this function.

error_log("There is something wrong!", 0);

The type parameter, if not defined, will be 0 by default, which means this log information will be appended to whatever log file is defined in the web server.

error_log("Email this error to someone!", 1, "someone@mydomain.com");

Here, the type 1 parameter will email an error log specified in the third parameter. To make this feature work, the PHP ini must have a proper SMTP configuration to be able to send out emails. These SMTP ini directives include host, encryption type, username, password, and port. This kind of error reporting is advisable to logging or notifying errors that need to be fixed as soon as found.

error_log("Write this error down to a file!", 3, "logs/my-errors.log");

To log messages in a separate file defined by the configuration of the web server, then type 3 must be used. The third parameter will serve as the location of the log file and must be writable by the web server. The location of the log file can be a relative path to where this code is called or an absolute path.

Log PHP errors through the web server configuration

To avoid changing parameters in the .htaccess or adding some lines in the PHP code to show errors, then the best way to log errors is defining it in the web server configuration file.

ErrorLog "/var/log/apache2/my-website-error.log"

For Apache, these files must be added to the virtual host of the specific website or application. This is usually located inside the sites-available folder for Ubuntu or httpd-vhosts file in Windows.

error_log /var/log/nginx/my-website-error.log;

For nginx, similar to Apache, the directive is just called error_log. For both Apache and nginx web servers, the log files must be writable by the web server. Luckily, upon installation, the folders for the log files of these two web servers are already writable.

Automatically collect PHP errors with Retrace APM

Retrace is an APM (Application Performance Management) tool offered by Stackify. But the tool goes beyond monitoring the performance of your application. It allows you to do centralize logging, perform code profiling, and stay on top of server and application metrics.


One of the great features of Retrace is its ability to automatically collect all unhandled errors in your PHP application. Our PHP extension will catch the exception and forward them automatically to Retrace.
With Retrace, all the errors are automatically logged and formatted so that it can be viewed easily. Retrace will not only show what errors have occurred but also analyzes where and what caused it. The time and number of occurrences are also shown in the logs so that it would be a lot easier to focus on which issue to prioritize.
To learn more about Retrace, please check out the Retrace feature page on error tracking.

show php errors

Conclusion

To further improve your PHP debugging process, it’s recommended to familiarize yourself with other built-in PHP functions. One such functions are debug_backtrace() and debug_print_backtrace(). These functions provide detailed information about the list of preceding function calls, which is invaluable when tracking a tricky bug.

Lastly, always remember to turn off error displays in a production environment. While displaying and logging errors during the development and testing phases is essential, it can also be a security risk. This is to prevent exposing potentially sensitive information to end-users.

In conclusion, error management in PHP is a crucial aspect of development. By understanding how to use error_reporting, display_errors, log_errors, and error_log string, you can streamline your debugging process. This will improve the overall quality of your PHP applications.

For a more comprehensive approach to error tracking and application performance management, consider using tools like Retrace. Retrace can automatically collect all unhandled errors in your PHP application. This will help you focus on what matters – creating fantastic user applications.

]]>
Why Should You Use PHP Frameworks for Web Development? https://stackify.com/why-should-you-use-php-frameworks-for-web-development/ Tue, 16 Aug 2022 12:52:42 +0000 https://stackify.com/?p=35781 PHP is a powerful, server-side programming language with numerous benefits and features. The language is extensively utilized to create various web development solutions.

However, core PHP may not be suitable to work on complex business requirements, as PHP code may get intricate. Also, efficiently maintaining complex applications built on PHP normally requires those who worked on the original project. Using outside developers to work on the code adds difficulty, time and expense you likely can’t afford.

Practically speaking, you need a better way to use PHP to develop a robust and easy-to-maintain web development solution. Also, you need an efficient approach to streamline development and ongoing maintenance. PHP frameworks offer the edge you need, giving you a quick and seamless method for developing web apps and websites.

PHP frameworks are a collection of various prebuilt components and libraries. They are used to reduce the complexity and expedite development by offering an efficient development approach that doesn’t require coding everything in PHP from scratch. Let’s take a deeper look.

What are the top PHP frameworks to look for in 2022?

There are dozens of PHP frameworks in 2022, each of which has excellent features. Laravel is a very popular framework among entrepreneurs, because it easily and elegantly supports a variety of web development solutions. All frameworks below support the MVC architecture, adding stability and structure to your development project. Moreover, you have many other options in addition to the top PHP frameworks below.

Reasons to use PHP frameworks in web development

PHP Frameworks are ideal for web development projects

Speed up web development

Time is crucial for any business website or web application. You need to launch on time to reap maximum benefit. As mentioned before, PHP frameworks help you create solutions in far less time than coding from scratch. Using a PHP framework is like working on a pre-built template with various components for basic functionalities like login, forms, server communication, HTTP, etc. A variety of other features and tools further accelerate web development speed.

Of course, quickly creating a web solution is only part of the process. Before you go live, you’ll want to load test your PHP website to ensure optimum performance under simulated traffic scenarios. Once in production, monitor performance with a full lifecycle APM solution to ensure a great user experience for every visitor.

No need to write additional code

Unlike some other programming languages, PHP uses long lines of code to express concepts. Therefore, programming PHP-based web development solutions is complex and lengthy. As a result, it takes immense time and effort to work out web development solutions using the PHP programming language.

On the contrary, PHP frameworks reduce the development time significantly. Many frameworks offer code generation features, enabling PHP developers to easily build clean and maintainable source code. Of course, you can easily rely on a PHP web development company to create a top-notch web development solution when budget allows. And you can bet that firm will be using a suitable PHP framework.

The MVC support

There are many benefits that you derive from using PHP frameworks during the development process. One such substantial advantage is the MVC architecture. MVC is a modern web development approach that PHP frameworks use to expedite and streamline the development process. MVC is short for Model, View and Controller and is an architectural pattern providing a robust and stable development structure. It separates the presentation layer from the business logic. Both the layers are connected via a controller that maintains the communication between the View and the Model layer.

MVC not only provides a quick way of developing web development solutions, but it also provides an efficient architecture for websites and web apps. With this structure, multiple developers can work separately on each layer of your project without compatibility concerns. MVC provides in-depth flexibility that enables you to create customized web development solutions quickly and easily.

Automate web development tasks

Developers have to perform several tasks besides writing the code during the web development process. Many of these tasks need extra time and effort to get the desired results. With core PHP, these additional tasks become even more time-consuming and difficult. As a result, project delivery times can be extended.

Using a PHP framework cuts down development time, because frameworks automate several tasks. With a framework, a PHP developer can automate common tasks like authentication, session management, caching and URL mapping. All this automation speeds up development time and enables developers to complete and deliver projects on time. 

Before you go live, you’ll want to load test your PHP website to ensure optimum performance under simulated traffic scenarios. Laravel provides an easy-to-use and expressive browser testing and automation API that simplifies web app testing via automation. However, most frameworks can be integrated with a testing framework. Symfony is another PHP framework that integrates with the PHPUnit testing framework seamlessly. Once in production, you’ll want to monitor performance with a full lifecycle APM solution to ensure a great user experience for every visitor.

Compliance with standards

Compliance with coding standards is another crucial benefit of PHP frameworks. Code compliances are the conventions and guidelines that need to be followed for better coding practices, methods, and approaches. A web development solution that follows these conventions and guidelines is well-structured, standards-compliant, and best in quality. Hence, compliance with the standards is essential if you want to create a web development solution with well-structured, readable, and quality code.

When you use a PHP framework, you can ensure that your web development solution is compliant with the standards. The frameworks were built with coding standards in mind. Therefore, these frameworks follow the necessary standards intrinsically. Thus, you can use PHP frameworks to create robust and standards-compliant web development solutions. 

Simplify maintenance

PHP frameworks simplify the maintenance of websites or web apps, by enabling PHP developers to write readable and maintainable code. Thanks to features like MVC and ready-to-use code snippets, interpreting and modifying code per your needs is simple. In addition, using a PHP framework eliminates potential issues of having one developer work on another developer’s code. Hence, PHP frameworks reduce the overall costs of developing and maintaining a website or web app. Thus you can take advantage of the PHP frameworks to create high-quality web development solutions with several benefits.

Final note

PHP is a leading technology in web development. It is both cost-effective and efficient for developing various websites and web apps. However, core PHP isn’t always suitable for creating more complex web development solutions for businesses. Therefore, PHP frameworks have become a sought-after choice in developing top-notch solutions. You can use PHP frameworks to build secure, flexible, high-performance websites and web applications.

A modern PHP framework is a beneficial and powerful tool in web development that solves many problems. It can help you save a lot of effort and time by employing the best of PHP along with its unique functionalities. You can utilize PHP frameworks to develop various web development solutions to meet your needs efficiently.

]]>
A Guide to Streams in PHP: In-Depth Tutorial With Examples https://stackify.com/a-guide-to-streams-in-php-in-depth-tutorial-with-examples/ Wed, 31 Jul 2019 16:39:08 +0000 https://stackify.com/?p=25844 You’ve already used PHP streams in your PHP development. However, they’re transparent, so you may not have noticed them. Streams are powerful tools.

In this article, you’ll learn to harness the power of streams in your PHP development and take your applications to the next level.

What are streams?

Streams provide on-demand access to data. This means you don’t need to load the entire contents of your dataset into memory before processing can start. Without streams, opening a 20MB file will consume 20MB of memory.

Most installations of PHP are set to use little memory—generally around 64MB. So working with large sets of data presents problems. Using streams allows you to interact with very large files in predictable and efficient ways.

It’s possible that in development your files are small enough not to cause a problem in this way, but in production, your system falls over. Using a remote monitoring service such as Retrace can help you stay on top of this.

Streams build on a uniform interface to access many types of data using a common set of functions and tools. It’s not an object-oriented interface, but it’s still polymorphism in action.

Through streams, you can carry out read and write operations seamlessly, regardless of the context of the data. So whether your context is the file system, TCP connection, or a compressed file, you can process your data with ease.

Every stream has an implementation of a wrapper. A wrapper provides the additional code necessary to handle the specific protocols or encodings. PHP has a number of wrappers built in. It’s also easyto write wrappers of your own to interact with other services and protocols.

Working with the file system

When using streams, working with the file system is exactly the same as working with any resource. I’m going to use the file system as an example, and then we can extend to some other contexts.

You reference a stream using a scheme and a target, like this:

<scheme>://<target>

The scheme is the protocol or wrapper that’s being referenced, and the target is the specific resource identifier.

As you’ll see, what the target actually contains will differ depending on the context. The default wrapper is the file system. That means you use streams every time you interact with the file system. You’re probably already familiar with other schemes, such as HTTP and FTP.

Let’s imagine you’ve found an enormous list of email addresses. In fact, you’ve found a billion email addresses that you want to loop over and do something to.

sharon@verizon.net
janusfury@att.net
timtroyr@live.com
danzigism@outlook.com
ryanshaw@yahoo.ca
ournews@icloud.com
improv@yahoo.ca
corrada@icloud.com
papathan@sbcglobal.net
mgemmons@mac.com
dinther@att.net
...

As you can see, each email address is on a new line, which will be helpful.

First, let’s try to open a large file without using streams.

<?php
$photos = file_get_contents(__DIR__ . '/big_file.txt');

If you run this, you’ll get the following error:

> PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1048576000 bytes)

Under the hood, this function uses a stream. Here, though, PHP reads the entire file at once into memory.

To succeed, use the on-demand capabilities of streams. Instead of trying (and failing) to load the entire file into memory, get a handle that you can use to access the data at various points.

<?php
$handle = fopen(__DIR__ . '/big_file.txt', 'r');

This is the same first argument as with the file_get_contents function. The second argument is a flag to signify the mode you want to open the file in. This could be read-only (‘r’) or write (‘w’) or any of a large number of alternatives.

You might have noticed that even though we’ve moved to streams, we haven’t added the scheme here. A different option is this:

<?php
$handle = fopen('file://' . __DIR__ . '/big_file.txt', 'r');

As the file scheme is the default, you don’t need to do this when working with local files.

You have a handle now! But how do you get to your data?

Reading from files

Two commands allow you to read from a stream. Both are nearly identical in function. We’ll use fgets(). You can also look at the alternative, stream_get_line(), if you wish. There are some minor differences that you may want to familiarize yourself with.

>>> $email = fgets($handle)
=> "sharon@verizon.net\n"

Awesome! You have your first line of text, including the \n delimiter character.

If you run it again, you get this:

>>> $email = fgets($handle)
=> "janusfury@att.net\n"

That’s the second email on the list—excellent!

But how does PHP keep track of where in the file it has gotten to? That information is in the $handle. This is a file pointer resource—a special variable that holds a reference to your external file.

To see where the interpreter has gotten to in a file, use the ftell() function.

>>> ftell($handle)
=> 37

Now that you’ve reached the end of the second email address, you’re 37 bytes into the file. If you want to, you can start over with the rewind() function.

>>> rewind($handle)
=> true
>>> ftell($handle)
=> 0

Now you have all of the tools to write a program that will do something with each email address in big_file.txt.

<?php
// Here is where you open my stream and get the handle.
$emails = fopen(__DIR__ . '/big_file.txt', 'r');

// You can use an infinite loop to keep going until you say stop.
while(1)
{
  // This is where you get the next email.
  $email = fgets($emails);
  // If it is blank, the stream returns false, so you can break.
  if (!$email)
  {
    break;
  }
  // This is where you can do something with the address.
  echo $email;
}

// Here you close the stream. PHP will do this anyway, but it's good practice.
fclose($emails);

Writing to files

A colleague asks you for a copy of the file in another directory. How can you do that? You can use two streams: one to read the original file line by line, and another to write to a new file in the same way.

<?php
// Open the source and destination stream.
$source = fopen(__DIR__ . '/big_file.txt', 'r');
$dest = fopen(__DIR__ . '/copy_big_file.txt', 'w');

// Wrap in an infinite loop, as before.
while(1)
{
  // Read the line from the file.
  $line = fgets($source);

  // Check that there's a data. If there isn't, break.
  if (!$line)
  {
    break;
  }

  // This is an alias of fwrite(), but it reads better.
  // The first argument is the destination stream, and the second is the data.
  fputs($dest, $line);
}

// Close the streams when you're done.
fclose($dest);
fclose($source);

Because you’re using streams, the memory footprint for this operation is low and constant, even if you’re working with huge files. There’s a built-in PHP function that does this for you— namely, stream_copy_to_stream(). Using this function, your script would be much shorter.

<?php
$source = fopen(__DIR__ . '/big_file.txt', 'r');
$dest = fopen(__DIR__ . '/copy_big_file.txt', 'w');

stream_copy_to_stream($source, $dest);

fclose($dest);
fclose($source);

You probably aren’t going to use PHP streams to move files around your computer. However, you can apply this knowledge to lots of other contexts. For example, you could use streams to move files from a client computer to a server, or even to several servers at once. Or you could process compressed files line by line, or read from a website and write to a disk. The possibilities are as endless as the types of data you can think of.

Stream wrappers

A wrapper is the code that tells the stream how to handle specific protocols. You can see what wrappers are on your server by using the function stream_get_wrappers(). On my local environment, I get this:

>>> stream_get_wrappers()
=> [
     "https",
     "ftps",
     "compress.zlib",
     "php",
     "file",
     "glob",
     "data",
     "http",
     "ftp",
     "phar",
     "zip",
   ]

That’s quite a list!

In the last section, you saw the default file wrapper in action. Most of the other wrappers here need no explanation. HTTP, HTTPS, FTP, ZIP, and others do what you’d expect. What about the PHP wrapper, though?

The PHP wrapper

The PHP wrapper allows access to the languages’ own input and output streams, along with access to temporary memory and disk-backed file streams.

To get access to the standard input stream, you can use php://stdin, which is read-only. In contrast, php://stdoutgives direct access to the standard out stream and php://stderr to the error stream, both of which are write-only.

The streams php://memory and php://temp are read-write, allowing temporary data to be stored in a file-like wrapper. The difference between the two is that php://memory will always be in memory, whereas php://temp will start writing to a temporary file when the memory limit is reached. This limit is predefined in the PHP configuration, and the default is 2MB.

<?php
// Here's how to open the temporary stream.
$temp = fopen('php://temp', 'rw');

// I'm generating some data here, but this will normally be your application.
for ($i = 0; $i < 1000; $i++)
{
  $string = $i . " green bottles sitting on a wall. \n";

  // Here's how to add the line to the end of the stream.
  fputs($temp, $string);
}

// Once you've finished collecting the data, you can rewind to the start to read it.
rewind($temp);

// This works in the same way as reading from the file system above.
while(1)
{
  $string = fgets($temp);

  if (!$string) {
    break;
  }

  echo $string;
}

fclose($temp);

There’s also php://filter, which is a meta-wrapper. It lets you filter your steam as you open it. This is useful with all-in-one functions, such as file_get_contents() or file_put_contents(), where you can’t apply other filters on a line-by-line basis.

<?php
file_put_contents("php://filter/write=string.rot13/resource=encrypted.txt", "My very secret string.");

This code filters the string “My very secret string” through the rot13 filter, a primitive encryption cypher, and then writes it to encrypted.txt in the current directory.

Stream contexts

A context is a set of parameters and wrapper-specific options that can enhance or otherwise change the behavior of a stream. You create a context using the stream_context_create() function. Most of the stream creation functions will accept a context array.

The most common use of stream contexts in PHP is to build HTTP headers.

<?php
// You can create an array of array with your custom values.
$opts = [
  // The top-level key is the wrapper you want to alter.
  'https'=> [
    // These are keys you may want to change.
    'method'=>"GET",
    'header'=> "User-Agent: MyCoolBrowser"
  ]
];

// You can change the default by using this function and passing the array of changes.
$default = stream_context_get_default($opts);

// Now the headers will declare your User-Agent as MyCoolBrowser when you get this file.
readfile('https://www.theguardian.com');

People normally change headers for much more practical reasons, such as to add tracking or verification. However, you can easily extend this trivial example to each of those tasks.

Using filters

A filter is a final piece of code that performs operations on data as it’s being read from or written to a stream. You can stack multiple filters onto a stream. I’ve already used the filters that come with the php:// wrapper. They were necessary for all-in-one file reads. However, it’s possible—and often desirable—to apply filters when working with more discrete chunks.

PHP comes with built-in filters. As with wrappers, you can use a function to find out which are active in your installation.

>>> stream_get_filters()
=> [
     "zlib.*",
     "string.rot13",
     "string.toupper",
     "string.tolower",
     "string.strip_tags",
     "convert.*",
     "consumed",
     "dechunk",
     "convert.iconv.*",
   ]

Some PHP extensions provide their own filters, so your list may differ greatly from mine. For example, the mcryptextension installs the mcrypt.* and mdecrypt.* filters, which are significantly more secure than our rot13 application earlier.

If for some reason you wanted all your email addresses to be in uppercase (or more likely, ensure they were all in lowercase), you could use a filter like so:

<?php
$emails = fopen(__DIR__ . '/big_file.txt', 'r');
stream_filter_append($emails, 'string.toupper');

Now when you use fgets() to read the email addresses, each character will be in uppercase.

Writing your own filter

PHP provides a base class PHP_User_Filter that you can extend to make your own filter.

The main worker method that you must override is filter(). The parent stream calls this method and receives the following parameters:

  • $in: This is a pointer to a group of buckets containing the data to be filtered.
  • $out: This is a pointer to a group of buckets for storing the converted data.
  • $consumed: This is a counter passed by reference that needs to be incremented by the length of the converted data.
  • $closing: This is a Boolean flag that is set to TRUE if you’re in the last cycle and the stream is about to close.

I’ve decided that I don’t like people knowing my name, Kevin. So I’ve written a filter to replace “Kevin” with “REDACTED.” Here’s the full code for the filter:

<?php
class NameFilter extends PHP_User_Filter
{
  private $_data;

  // This is called when the filter is initialized.
  function onCreate()
  {
    $this->_data = '';
    return true;
  }

  // This is the main function that does the data conversion.
  public function filter($in, $out, &$consumed, $closing)
  {
    // Here, I'm reading all the stream data into the $_data variable.
    while($bucket = stream_bucket_make_writeable($in))
    {
      $this->_data .= $bucket->data;
      $this->bucket = $bucket;
      $consumed = 0;
    }

    // Now I process it and save it again to the bucket.
    if ($closing)
    {
      $consumed += strlen($this->_data);

      // Here's where I set the data to replace and do the replacement.
      $pattern = "/Kevin/m";
      $str = preg_replace($pattern,
                          'REDACTED',
                          $this->_data);

      $this->bucket->data = $str;
      $this->bucket->datalen = strlen($this->_data);

      if(!empty($this->bucket->data)) 
      {
        stream_bucket_append($out, $this->bucket);
      }

      // This PHP constant indicates that the filter returned a value in $out.
      return PSFS_PASS_ON;
    }

    // This PHP constant indicates that the filter didn't return a value.
    return PSFS_FEED_ME;
  }
}

This is a silly example, but it might inspire you to think of your own. Maybe you want to add a title in front of each name or add a link for every company name that appears. If your company name appears, you might want to trigger an email alert. A filtered stream could help you do this. Also, you can carry out any string replacement or any operation on each chunk from the stream.

Registering and using your filter

Once you’ve written your filter by extending the PHP_User_Filter base class, you’ll want to register the filter and apply it to the stream.

$contents = '';

// Here's how to register a NameFilter with PHP for this life cycle.
stream_filter_register('myFilter', 'NameFilter');

// Open the stream as normal.
$handle = fopen("https://en.wikipedia.org/wiki/Kevin_Bacon", "r");

// Append your filter to the stream.
stream_filter_append($handle, "myFilter");

while(1)
{
  $line = fgets($handle);

  if (!$line)
  {
    break;
  }

  $contents .= $line;
}

fclose($handle);
echo $contents;

Running the script above allows me to see Kevin Bacon’s Wikipedia page. I have redacted “Kevin,” and now Mr. Bacon is known only as REDACTED Bacon.

Conclusion

I hope this article has sparked some ideas about using streams in your own code. I’ve really enjoyed digging deeper into these, and I have ideas for how to apply them to the codebases I work with.

Using streams with their various filters and contexts can make your code run faster and more efficiently. You can use services like Retrace to profile your code remotely. This profiling can help you identify bottlenecks. Maybe some of the tools and techniques from this article will help you improve your code.

If you’re looking for more PHP optimization tips, then this guide is very useful.

Start Free Trial
]]>
Symfony Performance Improvements: Tips and Techniques https://stackify.com/symfony-performance-improvements-tips-and-techniques/ Thu, 25 Apr 2019 20:01:14 +0000 https://stackify.com/?p=24458 Perhaps you came upon this post while looking at ways to improve Symfony performance. Or maybe you read our comparison of Laravel and Symfony and want to know more. You could have gotten here because you want to write a performant app from the start. Then again, you could just love reading all of Stackify’s blog posts. And who could blame you?

However you got to this post, or whatever goals you may have, I’m here to talk to you about Symfony performance tuning.

In today’s post, I’m going to cover Symfony performance tips that will help you get the most of your Symfony application. But I’m not going to start there. Instead, I first want to help you determine when you should start worrying about performance, and to consider where you should focus your performance improvements and where it would be a waste of time.

Once that’s established, we’ll dive into the tips and tricks that you can use. Some of these you can and should incorporate from day one. Others shouldn’t be used until you have a need for them.

Keys

So to kick this off, how do we know when we need Symfony performance improvements?

When should you worry about Symfony performance?

We often hear that premature optimization is the root of all evil. But what does that mean? Should we just write any code we want, as long as it works? Or should we put at least a little foresight into how we configure and run our application? And no matter which path we choose, what else should you do to make sure you’re taking care of performance concerns?

First, though we don’t want to spend too much time optimizing for performance issues we may never encounter, we do at least want to know what we’re getting ourselves into. For example, in our first section of the tips below, we’ll talk about some basic configuration that Symfony recommends when running applications. We don’t need to wait for bad performance before implementing those changes.

However, we also don’t want to run through the list of tips like it’s a to-do list that everyone must complete. Some Symfony performance improvements can benefit our application, while others don’t make much of a dent. But how do we know if a performance tip is worth implementing?

We can start by using Retrace to find our current application performance. We can also begin to monitor how that performance changes over time. And most importantly, we can discover where our performance suffers most for customers and hit the most critical spots with performance optimizations. Because if the customer doesn’t experience a performance issue, we shouldn’t waste resources on optimizing those last 40 milliseconds we can shave off. No one will notice that improvement, anyway.

Performance monitoring

You shouldn’t move forward with arbitrary performance enhancements without a baseline of performance metrics. Blind optimizations may not fix the performance issues that affect your customers the most. And they’ll take resources away from improving the real problems.

So if that wasn’t clear enough, let me state it simply. Don’t spend time making performance optimizations until (1) you know you have a problem and (2) you know where the problem is.

Now that’s out of the way, let’s start looking at what performance changes we can make.

What Symfony performance improvements can you make?

Now that we’ve discussed how we’d know that we need to make improvements, where do we make them? The following list will help you find a starting point. Some of these tips, like the first two sections, can and should be done at any time. The rest depends on your application and its performance metrics.

1. Upgrade to the latest and greatest

There are many reasons to upgrade to the newest versions of languages and frameworks. Hot new features make your life as a developer easier, while security improvements keep you and your customers safer from hacks and vulnerabilities. But relevant to today’s post, upgrading to the latest version can also improve performance.

Need some proof? Take a look at the changelog notes from some of the latest PHP versions and see how many times you can find the word “performance.” Almost every new version touches performance in some way. And the further behind in updates you get, the more your application performance can suffer.

Now you may say that upgrading takes time and energy that could be spent delivering new functionality. That’s true. So make sure you have a proper CI/CD pipeline that lets you upgrade your PHP, Symfony, and additional library versions quickly and easily. If things deploy smoothly, you’ll be able to get back to those business value stories after taking on the technical debt of upgrades.

So other than staying up to date, what else can you do?

keyboard

2. Optimize configuration

When looking at the configuration, you should review the documentation to see what settings are recommended. Though some configuration changes make little difference, if the documentation says you should change something by default, then you should take their word for it—that is, unless you have metrics or other proof that indicate you should go against their advice.

With Symfony, their docs provide some helpful information regarding configuration. Let’s look at some of these tips a bit closer.

Configure OPcache

Since we’ve covered why you should use the latest and greatest, we’re going to assume you use a newer version of PHP and can use the built-in OPcache.

But what is OPcache for? This cache provides in-memory storage of precompiled bytecode. That way, your application won’t need to load and parse scripts each time they’re used.

Let’s first enable OPcache in our application.

; php.ini

; For unix/Linux:
zend_extension=/full/path/to/opcache.so

; For Windows:
zend_extension="C:\full path\to\php_opcache.dll"

When using it out of the box, OPcache configuration should reflect best practices for Symfony apps. Therefore, we want to update the settings as follows.

; php.ini

; The maximum memory in megabytes that OPcache can use to store compiled PHP files.
; The current default sits at 128MB.
; Before PHP 7, this defaulted to only 64MB!
opcache.memory_consumption=256

; The maximum number of keys (and therefore script files) that can be stored in the cache hash table.
; The current default consists of 10,000.
; Before PHP 7, this defaulted to 2,000.
opcache.max_accelerated_files=20000

This config will provide better caching of scripts right away and give your customers a better performance experience, as the cache won’t fill up as quickly.

Additionally, we’ll want to configure OPcache to not bother with checking for file changes. Once you deploy your application, you shouldn’t be updating your code files on the server. And therefore, there’s no reason to have OPcache repeatedly check to see if your files changed.

; php.ini

; Tell opcache to not validate timestamps.
; Requires that you call opcache_reset() as part of your deployment process.
opcache.validate_timestamps=0

But when doing that, remember to call opcache_reset() as part of your deployment process. Otherwise, your newly deployed files won’t update in the cache.

Optimize Composer autoload

Similar to Laraval, Symfony will register various autoloaders by default. These provide assistance in loading aliases and classes for your application. And Symfony also uses Composer for determining how classes autoload within our application.

To optimize Composer autoload, we can use either composer dump-autoload or composer dumpautoload followed by our options. For my current version of Composer, if I look at the help docs, I can see the following options available.

The -o option will optimize the autoload to load with classmaps. That improves the performance of your application. It’s a bit slower than the non-optimized version, but generally, it’s recommended to use the optimize option in production.

Additionally, the –classmap-authoritative option enforces using only the classmaps and not defaulting to other loading methods if that lookup fails.

One other favorite flag improves performance. When running the application, the –no-dev option excludes test classes that don’t run during the normal application lifecycle.

3. Retrieve data efficiently

Next on our list of performance tips, let’s look at our data retrieval. Now, Symfony’s Doctrine ORM has its own best practices and tips. There’s too many to cover here. But let’s include a few tips that seem to come up often.

Let slow query log show you the way

query

This tip doesn’t apply just to Symfony, as it’s related to your database logs. If you suspect that you have slow queries in your application, you can identify them using a slow query log on the database layer. Now, this isn’t something you should have turned on all the time or in production, as it may cause performance issues of its own. But enabling it in a test environment will allow you to see what queries take the most time and where to focus your efforts.

Use eager loading

Symfony uses the Doctrine ORM to make getting data out of the database easy. However, if we don’t use Doctrine effectively, it can lead to performance issues.

For example, the code below will get all the items in our database with their MSRP price. Let’s say that we have 30 items from our store in the database. Also, the price lives in another table and not the items table. So if you were to profile this code, you’d see that you’re calling the database for every item in our list to get the price. That’s 31 calls in all.

{%for item in items %}
<tr>
<td>{{item.name}}</td>
<td>{{item.description}}</td>
<td>{{item.price.msrp}}</td>
</tr>
{%endfor%}

Instead, if we use eager loading, we’ll pull all the data we need upfront.

$q = Doctrine::getTable('Item')
->createQuery('u')
->leftJoin('u.Price p');
$items = $q->execute();

But as always, only apply eager loading if it makes sense. If you don’t actually need to get additional data from the database or if you only get it for one or two of the entities that come back, then lazy loading works well. Thankfully, our monitoring and metrics can help us make the right decision for our app.

Caching data

In addition to caching scripts, which we already covered, we can also cache data for faster access.

We have a few different options for caching data. First, we can enable the query result cache on frequently-run queries where the data rarely changes. For this, you can use Symfony’s OPcache. Or you can also use caches like Memecached and Redis. For this example, let’s use Redis.

<?php
$redis = new Redis();
$redis->connect('redis_host', 6379);
$cacheDriver = new \Doctrine\Common\Cache\RedisCache();
$cacheDriver->setRedis($redis);
$cacheDriver->save('my_cache_id', 'my_data');

In the example above, we connect to our Redis host and then set our cacheDriver to the Redis cache. Then, whenever we want to save data explicitly to our cache, we can call the save function on our cacheDriver.

Next, we can check to see if we have particular data within our cache.

<?php
if ($cacheDriver->contains('my_cache_id')) {
echo 'cache exists';
} else {
echo 'cache does not exist';
}

Then, let’s get data out of our Redis cache using fetch.

<?php
$my_cached_data = $cacheDriver->fetch('my_cache_id');

And finally, we can remove entries from our cache using delete or deleteAll.

<?php
$cacheDriver->delete('my_cache_id');
$deleted = $cacheDriver->deleteAll();

You can even use multiple caches to take advantage of different performance that they provide.

Consider skipping the ORM

My next tip might seem contrarian. However, we should always remember that different tools and technologies exist to fix specific problems. And if they don’t fix your specific application problem, then it’s valid to reconsider.

So why would we want to skip the ORM, since they make things easy. They map your database to your objects without much thought. But sometimes they can cause issues. That’s because hydrating, or deserializing, objects from the database into your classes takes time. And the larger the objects and their associates, the more of a performance hit you might take.

So once your application slows due to deserialization issues, you should be ready to take a different approach and look for alternatives. And perhaps it’s not an all or nothing solution. For example, you can cache your data in Redis or another cache to reduce the reads from the actual database. Alternatively, you can remove the ORM layer altogether.

But you won’t know if that’s the right move unless you have metrics.

metrics

4. Additional caching

In addition to database results, we have a few more things we can cache.

First, let’s look at HTTP caching. This isn’t specific to Symfony, but it can help give your application an edge in performance. The HTTP cache lives between your customer or client and your backend services.

Though most of our applications require dynamic data and loading, we usually have some parts of the application that don’t change often. By using HTTP caching, we can cache an entire page and skip calling our application server for everything but the first call.

What does this look like? In the example below, we add a @Cache annotation that controls the caching of the page that’s sent back to the client. In the example, we’ve added it to a specific page, but you can also add this annotation to an entire controller.

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;

/**
* @Cache(expires="tomorrow", public=true)
*/
public function index()
{
//....
}

And if you don’t want to cache an entire page, you can cache just fragments of it using edge side includes (ESI).

To use ESI, first, configure your application to enable it.

// config/packages/framework.php

$container->loadFromExtension('framework', [
// ...
'esi' => ['enabled' => true],
]);

And then render components separately with the render_esi function from Twig.

{# templates/static/index.html.twig #}

{# Load the dynamic page separately using a controller reference #}
{{ render_esi(controller('App\\Controller\\MyDynamicController', { 'myParam': 5 })) }}
{# or a URL #}
{{ render_esi(url('my_dynamic_page', { 'myParam': 5 })) }}

Then, each controller you use can be configured to cache differently, while still all loading data on the same page in your application.

Wrapping up Symfony performance

Though this post was about Symfony performance, one main point applies to everything. Without monitoring and metrics around your application, performance tuning won’t provide the best dollar value unless you optimize the right things. So whenever you’re tempted to start optimizing code, take a moment to add metrics or logging so that you can determine if optimizations are really necessary. And then you’ll also be able to see how much of an improvement your optimizations make.

Take a look at Retrace to see how Stackify can help with your monitoring to make sure you’re spending your development time focusing on the right code.

Schedule A Demo

]]>
PHP Debugging Tips https://stackify.com/php-debugging-tips/ Fri, 12 Apr 2019 18:33:21 +0000 https://stackify.com/?p=24431 Anyone developing software will sooner or later want to debug their code. It’s very clarifying to see your code execute step by step and inspect the values of variables at runtime. Developing with PHP is no different. In this article, we’ll have a look at PHP debugging, and I’ll also provide some tips and tricks.

Debugging

The term “bug” was first used by Thomas Edison, but was popularized by the celebrated Grace Hopper in 1947 when an actual moth was physically removed from a relay in the Mark II computer at Harvard. They even taped it to the log.

Debugging

Today, we define debugging as running the application while inspecting the existing variables and seeing the instructions that are currently run. This means the application waits for the developer to give the command before proceeding to the next statement. Usually, this happens in an editor or IDE. We call this interactive debugging.

Non-interactive debugging occurs when log statements are added to the code and inspected after the application has run. This is a crude way of debugging, but not necessarily a bad idea. For example, multi-threaded applications are notoriously hard to debug in an interactive way. Using a log to identify which thread did what is actually very helpful.

PHP Debugging

As a starting point, we’ll take this simple PHP file:

<!DOCTYPE html>
<html>
<body>
<form action="index.php" method="post">
<p>Your name: <input type="text" name="name" /></p>
<p>Your age: <input type="text" name="age" /></p>
<p><input type="submit" /></p>
</form>
<p>
Hi <?php echo $_POST ? htmlspecialchars($_POST['name']) : 'anonymous'; ?>
</p>

<p>
<?php
function getMessage($age) {
if ($age < 60) {
return 'You are '. (int)$_POST['age'] . ' years old.';
} else {
return 'You are of a respectable age.';
}
}

if ($_POST) {
$message = getMessage($_POST['age']);
echo $message;
}
?>
</p>
</body>
</html>

This renders a simple form that, when posted, produces the following result (I entered the posted values again for clarity):

Logging to the output

Let’s start with the most simple form of (non-interactive) PHP debugging: writing output somewhere so we can read it later. The easiest way to do this in PHP is to write to the document that PHP renders. In our example, we could simply add something like this to the code:

<!-- Posted:
<?php
if ($_POST) {
echo var_dump($_POST);
}
?>
-->

Notice how we wrapped our PHP code in an HTML comment. This allows the page to look the same as before. However, in the underlying source, we can now see the result of the “var_dump” call. This is what it looks like in my browser’s developer tools:

Of course, this info is still sent to the client, which isn’t ideal. You could potentially be exposing too much information about your application to people with bad intentions.

There are variations to this technique. For example, there are tools that will write certain information to the browser’s console instead of the HTML output, but they all involve sending data over to the client.

Another disadvantage is the need to write statements prior to running the application. For example, if we forget to “var_dump” a variable, we need to change the code and run the application again.

Your development environment

Before we continue with PHP debugging, I want to take a look at our development environment. PHP uses a php.ini file to control its behavior. When you install PHP, it usually comes with a php.ini-development and a php.ini-production file. On your local machine, or on a development server, you can safely rename php.ini-development to php.ini. This configuration will expose more information than you would want in a production environment. However, it’s useful information when you’re developing. On the production server, you’ll want to use the php.ini-production file.

One such setting is the “display_errors” directive. This means that any exceptions that are thrown during the execution of your application will be rendered to the user. For example, if we throw an exception in our “getMessage” function, we’ll see something like this:

Another interesting setting is the “error_reporting” directive. In development, it’s set to “E_ALL,” meaning PHP will report anything out of the ordinary. This includes best practices and coding standards. In a production environment, these checks would slow down your application too much. That’s why the production version of php.ini will exclude some errors.

If your changes don’t seem to have any effect, restart your web server. It doesn’t seem necessary when you’re running PHP on IIS on Windows, but your experience may be different.

It’s important to have a php.ini for development purposes and one for production servers. By splitting the configuration, we have access to useful information, while not exposing this to the outside world. Now let’s continue debugging.

Using Xdebug

Xdebug is a PHP debugging tool that’s been around for quite a while. There are alternatives, but Xdebug seems to be very popular, is actively maintained, and has good documentation. Because PHP runs on different platforms, I recommend using the Xdebug wizard to know which version to install and how. Once it’s installed, we can start using it.

It’s interesting to read the documentation on Xdebug about stack traces. You can configure it to render quite a lot of useful information when things go wrong. For example, this is what I’ve added to my php.ini file to configure Xdebug:

xdebug.collect_params=4 ;show full information about parameters passed to functions
xdebug.show_local_vars=on ;show any variables in local scope
xdebug.dump.SERVER=REQUEST_URI,DOCUMENT_ROOT,SCRIPT_FILENAME ;show these server variables
xdebug.default_enable=1 ;enable Xdebug

Our error now shows a lot more information that we can use to pinpoint the problem.

PHP Debugging Xdebug

We can now see the call stack, local variable, server variables, and what we passed to our function.

Interactive debugging with Xdebug

Now that we’ve set up non-interactive debugging, let’s look at interactive debugging. This is also called remote debugging.

Xdebug allows debugging clients to connect to it by using the DBGp protocol. This isn’t really important to us, except that it allows you to use almost any IDE or editor, as long as it (or a plugin) supports this protocol. Most major editors should be able to debug PHP with Xdebug. Check out the overview on Xdebug’s website for a list of supported clients. But even if you don’t see your favorite editor, it might still be possible. For example, Visual Studio Code isn’t mentioned, but there’s a PHP Debugging extension available.

To allow remote debugging, we need to add these two lines to our php.ini file:

xdebug.remote_enable=1 ;enable remote debugging
xdebug.remote_autostart=1 ;autostart, so we don't have to make a special HTTP request first

It’s very likely that you’ll have to configure your editor before it can connect to Xdebug. Check your editor’s documentation to see how.

If you’ve used the settings mentioned above, the editor will have to connect to the default port 9000. You can then interactively debug in your editor. For example, this is me debugging our application in Visual Studio Code:

Interactive Debugging Xdebug

We can now stop on breakpoints to inspect local and global variables, proceed through our application step by step, and even modify variables. In the screenshot above, I’m hovering my mouse over the “$age” variable and we can see its value.

Xdebug will connect to our editor for each request that we make. As long as our editor is listening for Xdebug, we can debug each and every request.

This is a much more powerful way of debugging than writing messages to the HTML we’re rendering.

PHP Debugging Tips and tricks

Now that we have the basics covered on how to debug PHP, let’s take a look at some tips and tricks. We’ve actually already covered three:

  • Use php.ini to expose information while developing, but avoid this on your production server.
  • Make PHP display errors.
  • Use Xdebug instead of writing messages to the output.

Now for some extras.

Traces

Sometimes, it can be useful to see the full trace of a request without using the remote debugger. For example, there might be a time when you want an overview of all the calls made so you can analyze it later. Xdebug allows us to create function traces by adding these settings to php.ini:

xdebug.auto_trace=1 ;immediately start tracing
xdebug.trace_output_dir=C:\PHP72\traces ;where to write the traces (must exist!)

For simplicity’s sake, I’ve set “auto_trace” to “1” so that Xdebug starts tracing all our requests immediately. This is useful if you want traces of any code in your auto_prepend_file.

Tracing everything is easy, but it can lead to a lot of trace files if we tell Xdebug to create a new file for every request, as we’ll see later. If you don’t want to trace every request, remove the “auto_trace” setting and add this:

xdebug.trace_enable_trigger=1 ;allow triggering traces
xdebug.trace_enable_trigger_value="secret" ;only if this secret is provided

With this, a call to “index.php” won’t trigger Xdebug to write a trace. But a call to “index.php?XDEBUG_TRACE=secret” will. You can also provide this in a cookie. This might seem like a clumsy way of doing things. Luckily, there are browser extensions to help you. For example, Xdebug helper for Chrome provides a simple button to help you switch tracing on or off.

Trace examples

One final interesting setting is “trace_output_name.” With our current configuration, Xdebug will always overwrite the same file. That’s why we can add this setting:

xdebug.trace_output_name=trace.%u

Xdebug will now create a new file with the timestamp in the filename.

For this example, I’ve artificially made our application a bit more complex to render a trace that looks like this:

TRACE START [2019-03-21 10:42:02]
0.4024 419112 -> {main}() C:\phpdebugging\index.php:0
0.4024 419112 -> htmlspecialchars('Peter') C:\phpdebugging\index.php:10
0.4025 419112 -> level1() C:\phpdebugging\index.php:41
0.4025 419112 -> level2() C:\phpdebugging\index.php:24
0.4025 419112 -> level3() C:\phpdebugging\index.php:28
0.4026 419112 -> level3b() C:\phpdebugging\index.php:29
0.4026 419112 -> getMessage($age = '8') C:\phpdebugging\index.php:42
0.4027 333064
TRACE END [2019-03-21 10:42:02]

This is a simple example, but traces can quickly become very large. Here’s a screenshot of only part of a Drupal trace for example:

Drupal Trace

The first column shows the time since the tracing started, in milliseconds. The second column shows the memory usage at that point in time.

If you add “xdebug.show_mem_delta” to your php.ini file, you’ll get an extra column showing you the difference in memory consumption. This is useful if you’re trying to find a function that uses too much memory.

There’s also “xdebug.collect_return,” which will add the return value of each function to the trace.

Finally, the “xdebug.collect_params” setting influences the tracing output too. It determines how much information is displayed regarding the parameters that were passed to functions. This setting also influences the Xdebug profiler, which we’ll see next.

Profiling

Profiling is similar to, but slightly different from tracing. It does the same as tracing, but it stores the information in a file that certain applications can open to show you a useful overview. It also provides a way of seeing how many times a function was called and how long the function takes to execute relevant to the overall request.

To enable profiling in Xdebug, you can add settings that are similar to the tracing settings.

xdebug.profiler_enable=1
xdebug.profiler_output_dir=C:\PHP72\profiler ;make sure this directory exists!
xdebug.profiler_output_name=profile.%u

Profiling can also be configured to work with the GET/POST parameter or cookie, just like tracing. And you can use the browser extensions here too.

I made our application a bit more complex again by adding some artificially slow functions. After making my request, there’s a new file in the directory I specified. There are several tools that can open a PHP profiling file. Have a look at the Xdebug documentation. I opened our profile file in PHPStorm:

PHPstorm

Again, this is a simple example. But in a real application, it can give you useful insights.

In the above overview, you can see

  • Callees: Which functions a function has called (i.e. the function’s “children”).
  • Callers: Which functions call the currently selected function (i.e. the function’s “parents”).
  • Execution Statistics:
    • Time: How much time was spent in this function, including time in the children.
    • Own Time: How much time was spent in this function, without counting the time in the children.
    • Calls: How many times the function was called.

For each statistic, you can see the absolute value and the percentage relevant to the entire profiling session.

Profiling and tracing allow us to debug performance problems. The application might work perfectly otherwise, but finding the cause of a performance problem is also part of debugging.

What about production?

When you need to debug an issue that happened in production, your safest bet is to reproduce it in a unit test. This allows you to consistently and continuously run in on your local machine, fix the issue, and be sure the issue remains fixed.

Unfortunately, this isn’t always possible. Sometimes, we have no idea how the issue occurred. Or it might be a combination of things happening in your application that you can’t reproduce easily. In any case, you could use a better view of your production environment.

One option is to install Xdebug on your production server. Only allow it to kick in when we provide a request parameter or cookie with the correct value. Be sure to keep this value secret!

However, Xdebug will have an effect on performance and even worse, might open your application to a malicious attack. This is where monitoring comes into play. A modern APM solution will monitor your running application. That way, you have access to the necessary information after the issue surfaced. Retrace supports PHP monitoring, including things like

  • performance monitoring
  • code profiling
  • error tracking
  • centralized logging
  • metrics

You can then use this information as a starting point to improve your code and fix bugs on your local machine.

Happy PHP debugging!

This post has given you several techniques on how to debug PHP applications. We’ve briefly touched on non-interactive debugging, but this is a simple way of debugging. A better way is to go the interactive route and use Xdebug. It gives us remote debugging with step-by-step execution of your code and variable inspection. There are also very useful tracing and profiling functions. Just be sure to do this on your development machine, not in production.

Bugs will always be part of any software. But with these PHP debugging tips, you’ll be able to understand and fix your applications faster and more easily.

]]>
How to Host PHP on Windows With IIS https://stackify.com/how-to-host-php-on-windows-with-iis/ Thu, 28 Mar 2019 14:59:01 +0000 https://stackify.com/?p=24306 Running PHP on IIS might not seem like a logical choice, but it can make sense. Luckily, getting PHP to run on IIS isn’t very hard, and gives you access to all the great PHP work that this community has produced.

What is PHP?

PHP was originally an acronym for personal home page, but now it’s short for PHP: Hypertext Processor.

PHP is a programming language used for web development. It’s also used as the name for the underlying engine that runs that application. Usually, this is the Zend Engine. Even though alternatives exist, the Zend Engine is the standard implementation and the only one regarded as “feature complete.”

The Zend Engine interprets the PHP code and compiles it on-the-fly to a format it can execute. This might seem inefficient, and it would be if the engine had to do so for every request, but some smart people have created optimizations as sufficient workarounds for most use cases. Incidentally, we will look at one such solution (WinCache) in this article. The advantages of PHP (like a great community and fast results) greatly outweigh the possible performance drawback most users won’t notice.

What is IIS?

IIS (Internet Information Services) is Microsoft’s web server and has been around since 1995. The latest version, IIS 10, comes bundled with Windows and as such, IIS is a free product.

There is a lightweight version of IIS called IIS Express that can be installed separately, but is intended for development purposes only. IIS Express only supports HTTP and HTTPS protocols and by default, merely supports local requests. In this article, I will be using the full version of IIS 10.

Since version 7, IIS has had a modular architecture, allowing us to add only the functionality we need. IIS 10 added support for HTTP/2, HSTS, and containers. IIS is the third most popular web server (after Apache and Nginx), running about 8.7% of all websites.

Reasons to run PHP on IIS

Most instances of PHP applications run on an Apache or Nginx web server, but there are valid reasons to choose IIS over other options:

  • Your system engineers have more experience with IIS.
  • You have a great support contract with Microsoft.
  • You have to run ASP.NET or classic ASP applications.
  • You develop Windows-only solutions locally on IIS, and also need to work on PHP solutions.
  • You need to integrate with other Windows services like Active Directory, Windows file shares, or Microsoft Exchange.

IIS only runs on Windows, but keep in mind that running PHP on IIS is not the same as running PHP on Windows. There are options to run PHP on Windows like XAMPP or WampServer. However, these two options make some additional choices for you. They run Apache as a web server and use MySQL or MariaDB as a database server.

This might not fit your needs. If you already have websites running in IIS, it’s a good idea to run your PHP websites there too. This way, they’re all in one place. Maybe you even want to use another database technology. Or you prefer the reliability of a solution provided by the big company that Microsoft is. We’ll look at installing PHP on IIS, and you’ll see that it isn’t that hard.

Try Stackify’s free code profiler, Prefix, to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby, and Python.

Installing IIS

If your machine isn’t running IIS yet, you will need to activate it. How to do depends on the specific version of Windows that you have. On a non-server edition of Windows, this is usually done in the “Turn Windows features on or off” dialog. The easiest way to open this dialog (on Windows 8 and up) is to open the Start menu and search for “windows features.” There, you should then be able to open this dialog. Once the dialog is open, check “Internet Information Services” and “CGI.”

IIS PHP

On Windows Server, there are more steps involved. Open the Server Manager application and go through the “Add Roles and Features” wizard. On the Server Roles page, select “Web Server (IIS)”:

IIS Web Server Roles

When you are prompted to select the server roles, be sure to enable CGI:

Server Roles

Once you have installed IIS, navigating to http://localhost should render the default IIS page:

Default IIS Page

What is CGI/FastCGI?

CGI is short for Common Gateway Interface, and is a standard protocol for web servers to execute applications on the server. It is important that you enable CGI in your IIS instance. In our case, this means that IIS receives the incoming web request, and then passes that on to our PHP engine (a simple Windows executable). The PHP engine will then return the output that IIS should return to the client.

CGI starts and stops the application for every request. This can become quite costly in terms of performance if you receive many requests. CGI also can’t handle database connection reuse or in-memory caching very well. FastCGI is a newer and better version of CGI created in the mid-90s to address these issues. FastCGI can keep processes alive over multiple requests and can reuse other resources, making it a faster and more modern alternative to “classic” CGI.

When you enable CGI for IIS, it will include FastCGI by default. IIS will then execute PHP over FastCGI.

Installing PHP on IIS with Web PI

The easiest way to install PHP on IIS is to use Microsoft’s Web Platform Installer. Web PI is a free package management tool to install non-commercial web development tools and their dependencies. When you run this tool, you can select the latest version of PHP under the Frameworks section of the Products tab:

Microsoft Web Platform Installer

Web PI will add several items to the install list (three in my case); then click on the big Install button at the bottom. Next, you will need to accept the license terms of the different components. If any components fail to install, you might have to install them manually. In my case, there was an issue with the PHP Manager for IIS, which I then just downloaded (from here) and installed.

It is also possible to install PHP manually, if you want more control.

Installing PHP on IIS manually

Installing PHP for IIS with Web PI will install it to “C:\Program Files.” You might want some more control over this, which is entirely possible and also not that difficult.

First, download PHP from the PHP website. Be sure to download a non-thread safe version. It isn’t necessary for PHP to do thread-safety checks, because FastCGI ensures a single-threaded environment. Removing these checks improves performance.

Extract the files to the folder of your choice; for example, “C:\PHP.” Also, add this folder to the Path System variable.

Next, open the Handler Mappings screen in IIS Manager:

IIS Handler Mappings

In the Actions pane, you will be able to choose “Add Module Mapping.” Enter the necessary details to tell IIS that *.php files should be run by php-cgi.exe through FastCGI:

Add Module Mapping

Now, select your server in the Connections pane of IIS Manager and choose “Default Document.” In the subsequent Actions pane, click “Add…” and add “index.php.” You can also add other files, like “Default.php.” This tells IIS to look for such a file, if no file is specified in the URL.

Finally, go to your PHP folder (e.g. “C:\PHP”) and rename either “php.ini-development” or “php.ini-production” to “php.ini,” depending on your environment.

Configuring PHP on IIS

If you’ve installed PHP on IIS by using Web PI, the defaults will probably be fine, but it doesn’t hurt to check. If you’ve installed PHP manually, you will definitely want to check the configuration. You can open the “php.ini” file and edit it if you’re familiar with configuring PHP. You can also open the PHP Manager in IIS Manager.

If you haven’t already, install PHP Manager for IIS from here. Then you will see it in IIS Manager:

PHP Manager

When you open it, you will immediately see a warning about your php.ini file. Clicking on the “View recommendations” link will give you an easy way of fixing any issues:

IIS PHP Configuration

WinCache and extensions

PHP allows extensions to be installed and enabled. In my default installation, I already had 40 extensions installed. You can install PHP extensions in the “ext” folder under your PHP installation folder. You can also install them through the PHP Manager. Likewise, you can enable and disable extension by editing the php.ini file or by using the PHP Manager.

For example, WinCache is a popular extension to improve the speed of PHP on Windows systems. It includes caching mechanisms like user data cache, session cache, file system cache, and relative path cache.

If you’ve installed PHP by using Web PI, you won’t need to do anything here. If you’ve installed PHP manually, download the correct version from SourceForge and save it to some temporary folder. Be sure to download from the development folder, because the other files are for the Web PI version of WinCache. Execute the “exe” file and then copy the “php_wincache.dll” file to the “ext” folder in your PHP installation folder.

In PHP Manager, you can then click on the “enable or disable an extension” link and enable WinCache:

PHP Extensions

The other option is to add “extension=php_wincache.dll” at the end of your “php.ini” file.

Make sure you download the WinCache version that corresponds with your PHP version. When I was writing this article, WinCache was only supported up to PHP 7.2, even though PHP 7.3 was already released. In the WinCache forums, you can read that support for 7.3 is on the radar, but requires some work.

Testing your installation

Now that we have installed PHP for IIS, we can test it easily. Create a new file in your favorite text editor and add only the following line:

<?php phpinfo(); ?>

Save this file to C:\inetpub\wwwroot. This is where IIS will be hosting your websites. Be sure to run your editor as Administrator, or you won’t be able to save the file to that folder.

Now, navigate to http://localhost/phpinfo.php in your browser and you should see a lengthy overview of all the current PHP settings:

IIS PHP Settings

This means everything is working great!

Keep in mind that putting a phpinfo.php file on a public website is a bad security practice. It exposes too much information about your server that hackers could use to attack you.

Combining the power of IIS and PHP

PHP is used by almost 80% of the websites on the internet, according to estimates. It has also stood the test of time very well. It has a vast and vibrant community and includes some tried and tested products such as WordPress and Drupal.

IIS isn’t the web server with the most significant market share, but it has the support and dedication of Microsoft behind it, meaning it will continue being developed and supported for quite some time. If you already have websites running in IIS, you can now add your PHP sites to it, keeping everything in one place.

In the example above, we added our (tiny one-file) PHP website to the wwwroot folder. This maps to the “Default Web Site” in IIS. However, nothing is stopping you from using the possibilities of IIS and putting your websites in other folders, then running them in separate application pools. It’s a best practice.

For example, I’ve extracted the Drupal files on my local machine and pointed IIS to that folder:

Drupal Files

Note: it is possible that this doesn’t work for you. I had to do some extra work because the default web.config generated by IIS includes a rewrite section that didn’t work for me. I had to either remove it, or install the rewrite module for IIS.

Here you can see the Drupal setup running on my local IIS instance:

Drupal on IIS

This is Drupal and PHP running on IIS 10 on Windows 10!

Further considerations

Just like any other application running on IIS, you want to take some things into account when running PHP applications on IIS:

  • Isolate applications from each other by running them in separate application pools.
  • Only let the application pool identity access the folder and files that belong to the website.
  • Consider having a php.ini file per site, instead of one global php.ini file.
  • Consider installing PHP in a folder that indicates the version (“C:\PHP7.2” instead of “C:\PHP”) so that different sites can rely on different versions of PHP.

There’s a lot more to running PHP on IIS, because of the power of both platforms (just like there are many possibilities when running PHP on Apache or Nginx).

An interesting thing to note is that Retrace will support running PHP on IIS soon. Retrace already supports many platforms and frameworks that run on or are often associated with PHP. But adding support for PHP on IIS will make it a great solution for your PHP APM needs, regardless of which web server is running your PHP applications.

PHP and IIS: easy!

Not many people know IIS supports running PHP applications and how simple it is to set it up. Using Web PI, you can have it working in just a few clicks. Installing it manually isn’t too hard, and it gives you some extra control.

Linux and Apache or Nginx seems to be the default choice for PHP, but in just a few steps, you can have your PHP applications running on your IIS web server. If for whatever reason, you don’t have the option of running Apache or Nginx and feel “stuck” with IIS, or you just prefer IIS, it shouldn’t stop you from using the power of PHP, still the most popular language on the internet.

]]>
Laravel vs Symfony: PHP Framework Comparison https://stackify.com/laravel-vs-symfony-php-framework-comparison/ Sat, 23 Mar 2019 15:59:19 +0000 https://stackify.com/?p=24236 Choosing a good PHP framework provides the right building blocks to make developing your app a breeze. Today we’re going to look at two PHP frameworks: Laravel and Symfony.

We’ll compare them, score them, and declare a winner. Along the way, you’ll choose the framework that’s right for you and your product.

Laravel vs Symfony: PHP Framework Comparison

PHP Framework Similarities

Both Symfony and Laravel provide cross-platform PHP frameworks and features that speed up the development of your PHP application. The scaffolding of the application helps define its structure, and the plugins extend your ability to add features quickly.

From a baseline perspective, both options start in a good place. What differentiates the two, however, depends on the specific application and developer needs.

PHP Framework Differences

It’s easiest to define differences by categorizing similar features and benefits. Once categorized, a series of questions start to emerge. Answer these questions, and the best option for your specific application should distinguish itself.

Popularity

Though you shouldn’t choose a PHP framework on popularity alone, there are some benefits a large user-base brings to a framework.

Laravel is the most popular PHP framework, but Symfony still ends up high on the list at number two.

With popularity comes a large amount of training and support information online. For Laravel, tutorials through Laracasts can provide excellent information that Symfony currently doesn’t provide. Though Symfony still shares great documentation, the resources are not as extensive as those for Laravel.

Laravel: 1 
Symfony: 0

Performance

In older versions, Laravel performed better than Symfony.

However, with improvements in Symfony 4+, Laravel’s edge shrunk down close to nothing. The performance gains that Laravel once boasted might not be there anymore.

As long as you’re using the latest and greatest version of each PHP framework, performance is a toss-up. Therefore, there’s no change in score.

Laravel: 1 
Symfony: 0

PHP Framework Performance

Modularity and scaling

Symfony contains reusable components, which provide more modularity. It organizes the code in a cleaner way, making it a great fit for larger and more complex projects. This is why many experienced PHP developers prefer Symfony over Laravel.

Additionally, Laravel’s strength revolves around MVC-based apps. Once you start to wander away from the MVC paradigm, Laravel can’t help you.

Using Laravel to get up and running will leave your Symfony cohorts in the dust thanks to a useful set of pre-built dependencies that you’ll need. However, if you’re building a large scale application, picking and choosing your dependencies and plugins makes the application easier to enhance and scale. For this section, the point goes to Symfony for flexibility and modularity.

Laravel: 1 
Symfony: 1

Pro Tip: As you begin to scale and projects become larger and more complex, consider using an APM tool like Retrace to help monitor code and identify errors in the pre-production pipeline.

Templating engine

PHP in itself is a templating engine.

However, providing additional templating engines provides more advanced templating with less syntax. Using other templating engines helps keep the business logic in the PHP and presentation logic within the templating engine.

While Symfony provides Twig as the default templating engine, Laravel provides a bit more.

Laravel’s default templating engine Blade has lots for everyone, Blade provides advantages over Twig, as it allows for code reusability that doesn’t exist in Twig. Additionally, Laravel brings in Lumen, a sub-framework for building APIs and microservices. Bonus!

Laravel: 2 
Symfony: 1

Templating Engine

Database support

Both Laravel and Symfony provide object-relational mapping (ORM) for data access. With Symfony, Doctrine handles ORM, while Eloquent provides ORM for Laravel. With ORM, data manipulation becomes much simpler in either PHP framework.

There are a number of database-related differences between the two PHP frameworks.

Out-of-the-box support

First, let’s look at what databases each PHP framework supports.

DatabaseLaravelSymfony
DrizzleX
MySQLXX
OracleX
PostgreSQLXX
SAP Sybase SQL AnywhereX
SQLiteXX
SQLServerXX

As you can see with the table, Symfony provides a few additional options. So, if you’re going for breadth, Symfony wins this one.

Database migrations

With Symfony, database migrations are automatic. They just need simple definitions for the fields in the model. So that seems like a quick win, but let’s look further. When considering Laravel, database migrations are manual, but they don’t require defining the fields!

Data modeling

With Laravel, accessing the data requires more knowledge of SQL. That’s not the case with Symfony, although it requires that you create a repository function for each call. If your application uses a complicated database structure, that may result in a large number of repository functions.

On the other hand, Eloquent tends to tie your application to your DB schema design. Changing a column name could result in changes throughout your codebase. Doctrine, and Symfony, by extension, use a mapper pattern, so you can delineate between your database schema and your business objects and logic.

Taking all of that data into account, I’m going to go with Symfony for this

Laravel: 2 
Symfony: 2

FYI: If your app relies on a database, you know that problems in the database often have wide-reaching impact downstream. Retrace’s SQL Monitors are a great way to more proactively keep tabs on data and database health.

Final score

There’s not a particular technology that’s better across the board.

It all depends on what problems you have and which technology can best solve those problems.

Try both to see which works best for your use case. Experiment and play with the features that are most important to you.

In either case, you can use Retrace to monitor your PHP app. Head on over to the getting started section to see how easy it is to set up.

Retrace
]]>
PHP Error Log Basics https://stackify.com/php-error-log-basics/ Sat, 16 Feb 2019 15:53:08 +0000 https://stackify.com/?p=23921 When developing PHP applications, error logs tend to be underutilized due to their apparent complexity. The reality is that PHP error logs are extremely helpful, especially when configured and used properly.

While there are advanced tricks to truly squeeze every last drop of utility out of error logs, this article will cover the basics of configuration and the most common use cases so you can get up and running quickly.

Once you’ve gotten comfortable using error logs effectively, you can move on to more advanced tools for further enhancing your PHP development productivity.

Setting up PHP error logging

To enable error logging for your site or application, follow these steps:

  • Locate the php.ini file on your server.
  • Look for the line containing the error_reporting entry.
  • Ensure it is not commented out, i.e. with a semicolon (;) in front of the entry.
  • Set the error_reporting entry equal to the desired level of logging (covered next). For example, you might set it to error_reporting = E_ALL.

Error reporting levels

There are numerous reporting levels to allow you to select exactly what you’d like to be notified of. Below are some of the most commonly used ones. A full list can be found in the official PHP documentation.

  • E_ALL—Logs all errors and warnings
  • E_ERROR—Logs fatal runtime errors
  • E_WARNING—Logs non-fatal runtime errors
  • E_NOTICE—Logs runtime notices (typical bugs in code)

As a final step in the basic configuration of PHP error logging, you’ll want to decide whether or not to display the errors on the client (browser). This is easily done:

  • Look for the line containing the display_errors entry in the php.ini file
  • Ensure there is not a semicolon (;) in front of the entry
  • Set the display_errors entry to On or Off. For example, display_errors = Off will not show errors on the client

Where are the error logs?

Once you’re all set up with logging and generating plenty of errors (for practice, of course!), you’ve got to actually look at them to determine what’s going on.

The default error log tends to differ from environment to environment, so it’s advisable to manually set the location of the file. Here’s how:

  • Look for the line containing the error_log entry in the php.ini file
  • Ensure there is not a semicolon (;) in front of the entry
  • Set the error_log entry to the desired path of the log file. For example, you might use error_log = /logs/php-errors.log.

Note this, though: you’ll have to restart your server for the changes to the php.ini file to take effect.

How to use PHP error logs effectively

There are a number of handy error logging functions built directly into the PHP engine, which should be enough to cover basic use cases. Of course, when your codebase gets to a point where it needs more advanced solutions, something like Stackify’s post on PHP logging best practices may be what you’re looking for.

Some of the more commonly used error logging functions are covered below, but you can find a comprehensive list (naturally) in the official PHP documentation.

error_log()

The error_log()  function allows for a string (required) to be sent to the log file. The message can also be sent to an email address. There are a few other options, but they’re more advanced so they won’t be covered here.

In its most basic form, error_log() writes a message to the error log:

error_log(“There’s been a problem!”);

Using this function to troubleshoot data structures or variables is fairly straightforward as well. Here’s an example:

$toolsArray = array("Retrace", "Basic Error Logging", "Hammer");
error_log(print_r($toolsArray, true));

In this way, the contents of the variable sent as the first parameter of the print_r() function will be displayed in the logs, which is a great way to keep track of data that may change over time or needs to be monitored during development.

debug_print_backtrace()

While viewing code backtraces isn’t typically done via the error log files, it can be helpful for smaller applications or when getting familiar with troubleshooting.

The most readable way to send a backtrace to the log file is the following:

ob_start();
debug_print_backtrace();
error_log(ob_get_clean());

This utilizes PHP’s built-in buffer as well as the previously mentioned error_log() function to provide some insight as to the source of errors produced by an application.

Clean up after yourself

PHP error logs don’t typically clear or truncate themselves by default. As such, good practice suggests you only enable logging when needed during development and you delete log files when they’re no longer needed.

Where to go from here

Now that you’ve got all the tools for effective error logging in PHP, you can debug with confidence and eventually explore some more advanced utilities like Retrace. Retrace allows you to see the error in context with the rest of your logging messages. These additional insights will give you a trail into what was happening leading up to the error.

Start sending your logs and errors to Stackify by signing up for a free trial.

Have fun and happy coding!

]]>
A Detailed Guide to PHP Debugging https://stackify.com/php-debugging-guide/ Thu, 31 Jan 2019 17:40:05 +0000 https://stackify.com/?p=23819 If you use PHP or you find yourself “adopting” a PHP app (like I did a few years ago), you must know how to debug PHP.

In this detailed guide to PHP debugging, you’ll see some debugging techniques that apply to almost any programming language. But don’t worry. I’ll get into the specifics that apply to PHP, from the basics all the way to fully integrated debugging techniques. Let’s start with a basic technique in PHP debugging: outputting and logging values.

Outputting values

When you need a simple way to debug programs and you have no other options, you can usually output values. Sometimes this means doing a var_dump or logging a whole series of events.

It’s useful to have debug logging in your program. In PHP, you can use various loggers to log debug messages. When the program is run in debug mode or the log level is set to debug, these messages will end up in your stdout, stderr, or log files. The logs will fill up pretty quickly in “debug mode,” so you only want to turn it on temporarily. But I’m getting ahead of myself here. Let me backup to some simple ways to output values.

Dumping variables to stdout

The var_dump function is one way to see what’s happening in your PHP program. It’ll dump a variable value to stdout. There are other functions you can use for debugging through outputs. Here are a few and how they’ll help you:

  • var_dump ($var) dumps the variable type and value to stdout.
  • print_r ($var) prints the variable value in human-readable form to stdout.
  • get_defined_vars() gets all the defined variables including built-ins and custom variables (print_r to view them).
  • debug_zval_dump ($var) dumps the variable with its reference counts. This is useful when there are multiple paths to update a single reference.
  • debug_print_backtrace() prints a backtrace that shows the current function call-chain.
  • debug_backtrace() gets the backtrace. You can print_r, log it to a file, or send it to a logging endpoint asynchronously.

Here’s sample code that exercises each of these useful debugging functions:

<?php
$myVar = "hello world!";

var_dump($myVar);
print_r($myVar);

$allVars = get_defined_vars();
print_r($allVars);
debug_zval_dump($allVars);

function sayHello($hello) {
    echo $hello;
    debug_print_backtrace();
}

sayHello($myVar);
?>

These functions are a quick way to debug your PHP code. You can see them in action in this Paiza. Each function has a purpose and can be useful for debugging.

Switching error reporting level

PHP has a few ways to configure error reporting. You can use the php.ini file, if you have access to it. Otherwise, you might use the htaccess configuration. If you can’t use configuration files, you have the option of changing the values via a script. This is possible, but think about how you would change modes after deploying your application.

A combination of settings will get you the right levels of error logging. You’ll want to consider the following settings:

  • error_reporting sets the level of logging. E_NOTICE is useful during development since it will tell you about defects such as unassigned variables.
  • display_errors tells PHP if and where to display error messages.
  • display_startup_errors should only be used when debugging.
  • log_errors and error_log work together to send errors to a log file. Do this in production rather than displaying them to end users.

The PHP manual spells out these settings in more detail and provides more information I could ever fit in this section. But even with the best logging settings, you still need to monitor for errors.

Monitoring error logs

It’s one thing to log errors—that’s almost a given. It’s a whole other thing to take action when errors are logged. First, you have to know about the errors. Unless you have all day and night to hover over the logs, you will not know when something bad is happening!

The best thing you can do is send your PHP logs to a service that will handle a few key things for you:

  1. Log aggregation. You want to see all your logs in one place. If you can centralize your logs and metrics across instances, that’s even better! You’d be able to spot trouble wherever it happens.

image

  1. Alerting. There’s nothing better than automation. If you’re a programmer, you know what I mean! You’ll want to automate almost anything if you can. Alerting is a way to send alerts automatically to a group email (better than an individual for continuity) when there’s a problem. This can be a server issue or errors hitting your logs. It should be configurable and you should have control over the configuration.
  2. Traces in your logs. What’s a trace? It’s not just a stack dump that lets you see what was going on when an error happened. It’s also a way to track performance, which is often a sign or a cause of a bug.
  3. Deduplication of log entries. When a bug causes an error, it can fill up the logs pretty quickly. Just combing through the logs with hundreds or thousands of the same entry is a showstopper. Deduplication takes away the pain!

You can configure many of the PHP logging utilities to work with Stackify Retrace by following this guide. Retrace works with PHP, and it does all of these things for you. Plus, it automatically collects lightweight traces—and only when it should.

Sure, Retrace is a great tool for detecting bugs! But once you detect them, fix them. Often that means attaching a debugger. Let’s get into that next!

Stepping through code

Now we will talk about debugging by stepping through code. This is what many of us developers think of when we see “debugging.” It’s a common way to debug code (remove defects that cause errors). With a web app or website, debugging is often two-pronged.

Once notified about an error that’s been logged, we can debug if needed. With enough detail in the logs, this should be easy. We might not even have to use a debugger. Often, the less use one, the better. But if you do, here’s how to tackle that!

PHP debugging tools

You can debug PHP using one of many debugging tools to attach a debugger client. PhpStorm works with debug utilities like Xdebug and ZendDebugger.

Being a polyglot, I need an IDE that supports multiple languages, so I’m opting for VS Code these days. I’ve used Xdebug with Visual Studio in the past, so let’s see how we can set it up with VS Code.

The debug server setup is the same, but each client (IDE or CLI) will have a slightly different setup. See, the debug server (a Zend extension) opens a port, and the client communicates with the server through that port. It’s just a matter of configuration and installing the right components.

Here are the steps I’m taking on this journey:

  1. Check for PHP extensions in VS Code. There are plenty! The top of the list looks like this:
    phpdebugAnd in case you’re missing it, PHP IntelliSense is on top with over six million downloads, followed by PHP Debug, with over three million.
  2. Install the PHP Debug extension.
  3. Click “reload” to reload VS Code.
  4. Install Xdebug. The PHP Debug extension for VS Code is only an integration to Xdebug. I have PHP 7.0 installed, so I must get the right version of Xdebug from the download page. The following script will help:
<?php
phpinfo();
?>

I’m looking for the PHP version, compiler version, architecture, and PHP Extension Build so I can download the correct version. I have x86, VC14, NTS (Non-thread-safe). This version came with WordPress for IIS. I’m working on a Windows machine. If you’re on a Linux box, you won’t face these same issues… just compile the source code for Xdebug!

  1. Now I have the right version, I will put it in the PHP/ext directory.
  2. Next, I need to configure PHP to use the extension and allow remote debugging. I’ll add the following configuration to the php.ini file that’s listed in PHP Info:
; set the extension path
zend_extension="C:/Program Files (x86)/PHP/v7.0/ext/php_xdebug-2.6.1-7.0-vc14-nts.dll"
; allow remote debugging
[XDebug]
xdebug.remote_enable = 1
xdebug.remote_autostart = 1

This’ll set up the PHP server to use XDebug. The steps here are the same no matter what IDE you use. Xdebug opens an HTTP port so that your debugger can attach. The client still needs to be configured to attach and use the debugging protocol. I will run through that part now.

  1. Finally, I will configure VS Code to connect to Xdebug. There are a few simple steps and then attaching is automatic. I’ll break this out into its own section since there are a few steps.

Configuring your IDE

After installing Xdebug, you still need to configure your IDE to attach to the debugger. In VS Code, this means adding a debug configuration. Fortunately, this is automatic at this point. It’s just a few simple steps:

  1. Switch to the debug view.
  2. Click the gear to bring up the languages menu.image
  3. Select PHP. VS Code will generate the default configuration.image
  4. Reload the PHP server. I’ve installed another extension called “PHP Server” that makes this simple. Use the context menu (right-click) to control the PHP server as shown in the screenshot below.image

This should put our IDE in a state that’s ready to attach to Xdebug. Communications with the debugger happen through a TCP port on the debug server. Xdebug uses the DBGp protocol through port 9000 by default.

Now we’re configured, let’s look at the mechanics of a debug session. Next, we’ll cover how to get into a debug session, how to set breakpoints, and how to step through, into, and over functions. It’s the best part!

Attaching and stepping into debugging

And now, the moment you’ve been waiting for: step-through debugging. We’ve already configured our environment for debugging. We’ve installed a debugging extension (specifically Xdebug), and we’ve configured our IDE (VS Code, in my case). Now it’s time to attach to the debugger.

Attaching a debugger

The PHP Debug extension for VS Code generated a launch.json file. That file goes into a .vscode directory in the root of the project. Here’s what it generated:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387

    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9000
        },
        {
            "name": "Launch currently open script",
            "type": "php",
            "request": "launch",
            "program": "${file}",
            "cwd": "${fileDirname}",
            "port": 9000
        }
    ]
}

It’s adding two launch configurations. Those are available in the debug view. We can either attach to a running server or launch a new one with the current script. Since I have phpinfo running already, I’ll start there by choosing Listen for XDebug to attach to that server.

Once you’re attached, you will see the debug toolbar.

image

Most debuggers have a similar control mechanism. This allows you to start, stop, step, and restart your debugger. Since we see a stop and pause icon, we’re attached and ready, so let’s get stepping!

Stepping through code

Stepping through code is as much an art as it is science. The first thing you need to do is set up a breakpoint where you think you have an issue. I’ll usually plug one in just before so I can see what’s happening as we step into the problem code. Let’s set one in the phpinfo script just to get things rolling.

Setting breakpoints

Usually, clicking in the left margin will set a breakpoint on the nearest line. You can also set your cursor on the line and hit F9. If you’ve got multiple functions calls on the same line, that’s a way to ensure the breakpoint is on the right one. A red dot should appear in the left margin. This shows a breakpoint. It should also be listed in the “breakpoints” component. Here’s an image to clarify:

image

Note: we’re still in the Debug view. I set a single breakpoint. Now, when I right-click the red breakpoint circle in the margin next to the code, you can choose Edit breakpoint… to set up conditions if you need to. Conditions are useful, especially if you have an entire collection but only one element is causing an issue. I use conditionals all the time!

Besides conditional breakpoints, you have the option to log a message and break after a certain number of hits. The latter is useful when you have code that repeats without a specific unique value to trigger a break on. For example, you might have code to render components in a collection of components. If the 13th component causes a catastrophe, you can just set the hit count to 13. I’ve had to count manually too many times to see the value in this feature!

With at least one breakpoint set, you’re ready to step through your code.

Stepping through code

Stepping through code is a complex operation. It’s simple to control, but there’s a lot going on. The debugger will evaluate variables, you can set watches on variables, and you have access to the call stack. Once the debugger is paused on a breakpoint (or by manually hitting the pause button/pressing F6) you’re ready to step through the code.

Use this script to follow along:

<?php
phpinfo();

function step_over_me() {
    echo 'stepping over me';
}

function step_into_me() {
    step_over_me();
}

for ($i=0; $i < 100; $i++) {
    step_into_me();
}

?>

You can step into functions (F11), step out of functions (Shift + F11), and step over functions (F10). You should get used to using the function keys to drive your debugging sessions; they’ll go a lot smoother if you do!

Some languages allow you to go backward in time. PHP doesn’t, but that’s OK. It’s a scripting language, and that would cause issues with declarations, anyway. Let’s step through this script by using F10.

Place a breakpoint on the phpinfo line. With your PHP server serving the page and your debugger attached, reload the web page. If all goes well, your debugger will light up and pause on that line.

image

Congratulations! You now have an active debug session. Follow these steps to move along through the code:

  1. Press F10 a few times and watch the debugger step through the code.
  2. When you get into the loop, step into a method with F11.
  3. Once you’re inside the method, you can use Shift + F11 to step back out. All the code will still run—it’s just that your debugger won’t follow those parts.
  4. You can use F5 to get out of the loop and continue to the end (or the next breakpoint, if there is one).

TIP: Browser debuggers use F8 to continue since F5 is already mapped to a page reload. This little mismatch can trip you up when you switch between browser tools and your IDE.

Skipping a loop

It’s easy to skip a loop. Just set a breakpoint just past the loop and use F5 to skip ahead to that point.

image

Often, you want to step into the loop at least once before you pass it by. Use F11 to step into it. Wrap loops in functions so you can step out with Shift + F11 and not lose a beat!

There’s another option, if it’s available to you. It’s run to cursor, and it does what it sounds like. Just place your cursor somewhere past the loop and use this option to jump to that point.

image

The debugger will run from its current position to the cursor when I select this option. Notice that there’s no keyboard shortcut for it, unfortunately.

Checking variables

One key benefit of debugging is that you can check variables as you step through the code. Most IDEs include a way to check local and global variables. Also, you can watch variables so you don’t have to hunt them down in Locals or Superglobals.

You can also watch expressions! This is great when you want to see how a complex expression inside an if statement will evaluate. Just copy the expression into a watch and you can track the result as values change.

image

I’ve added the following watch expression: $path == “blah”. In VS Code, you can highlight an expression in the code and open the context menu to watch the expression.

image

I’ve highlighted $i < 100 to add it to my watch expressions. You can also evaluate any expression in the debug console!

Evaluating in debug console

You can evaluate expressions in the debug console too. If you need to check something once, it’s better to evaluate it in the console.

Open the debug console and enter the expression.

image

You can also check the context menu for an option to evaluate the selected expression. Here are things you can do in the debug console:

  • Set new variables.
  • Change variable values.
  • Execute functions (in most cases).
  • Evaluate expressions (e.g., $i == 55).

These frequently come in handy for debugging!

Wrapping things up

We’ve covered a lot in this post. It’s enough to get you started with PHP debugging. This is a highly in-depth topic, but the best way to learn is by doing. Practice debugging until you’ve mastered the technique, and you’ll earn a reputation as a bug exterminator extraordinaire!

]]>