To give back to our community of developers, we looked at our database of thousands of projects and found the top 10 errors in PHP apps. We’re going to show you what causes them and how to prevent them. Avoiding these "gotchas" will make you a better developer.
Because data is king, we collected, analyzed, and ranked the top 10 PHP errors. Rollbar collects all the errors for each project and summarizes how many times each one occurred. We do this by grouping errors according to their fingerprints. We group two errors if the second one is just a repeat of the first. This gives users an excellent overview instead of an overwhelming big dump like you’d see in a log file.
We focused on the number of projects experiencing an error because we wanted to see the errors that affect the most developers in different companies. If we looked only at the number of times each error occurred, high-volume customers could overwhelm the data set with errors that are not relevant to most readers. The errors below are the ones most likely to affect you and your company.
We'll describe each error in more detail starting with the most common. At the end, we'll share best practices to avoid shipping them to production.
1. PHP Parse error: syntax error, unexpected end of file
A parse error occurs when code that contains a syntax error is executed. Syntax errors needn’t be large, not complicated, as the following example demonstrates.
$test= "test"
The code will throw "PHP Parse error: syntax error, unexpected end of file
because it is missing a semicolon at the end of the statement. The example below will execute successfully.
$test= "test";
2. E_WARNING: Invalid argument supplied for foreach()
Introduced in PHP 4, the PHP foreach construct provides an easy way to iterate over arrays and iterable objects, such as those that implement the \Traversable
interface. Try to use it on a variable with a different data type or an uninitialized variable. It will issue an error, such as in the example below.
$y_exceptions = null;
foreach($y_exceptions as $thisException) {
}
The above code throws a warning with the message "Invalid argument supplied for foreach()”, because $y_exceptions
is not an array nor does it implement ArrayAccess
, \Traversable
, or any of the other iterable interfaces.
3. QueryException: SQLSTATE[23000]: Integrity constraint violation
The exception occurs when our code does attempts to perform a SQL operation which would cause violate an integrity constraint, based on the database schema’s. This error could be caused for a number of reasons, including attempting to insert a duplicate primary key value into the table, or not providing values for one or more required columns.
CREATE TABLE testtable(
user_name varchar(255) NOT NULL PRIMARY KEY,
password varchar(255)
);
$user_name="test";
$data=array('user_name'=>$user_name);
DB::table('testtable')->insert($data);
$data=array('user_name'=>$user_name);
DB::table('testtable')->insert($data);
In the above example testtable
has a column user_name
with the primary key constraint. We are trying to insert duplicate value in the user_name
column.
4. QueryException: SQLSTATE[42S22]: Column not found:
Another exception may occur when your code attempts to operate on an undefined column. The following example demonstrates this.
$user_name="test";
$data=array('user_name'=>$user_name,'password'=>$password);
DB::table('testtable')->insert($data);
In this case it is throwing a "Column not found" exception because we are trying to insert a value into testtable
’s password column, which does not exist.
5. GuzzleHttp\Exception\ClientException:Client error
Guzzle is a PHP library that makes it trivial to create HTTP clients for sending HTTP requests and integrating with web services. If errors occur during a transfer attempt, it will throw an exception. Specifically, it will throw a GuzzleHttp ClientException
to handle HTTP 400 errors, if the http_errors
request option is set to true.
This exception extends from BadResponseException
and GuzzleHttp\Exception\BadResponseException
extends from RequestException
. The example below helps us understand the error.
$client = new \GuzzleHttp\Client();
$res = $client->request('GET', 'https://httpbin.org/status/404');
The example throws the client exception "Client error: GET https://httpbin.org/status/404
which resulted in a 404 NOT FOUND
response".
The root cause of such types of error may be the following:
- Request syntax error
- Wrong api version
- Unsupported media types
They can be handled using a try catch block. The example below shows how to do so.
try {
$client->request('GET', 'https://httpbin.org/status/404');
} catch (ClientException $e) {
echo Psr7\str($e->getRequest());
echo Psr7\str($e->getResponse());
}
You can see that the code’s wrapped in a try/catch block, which will catch any ClientException
’s that are thrown. You could extend this example to catch other, more specific, extensions, such as the ones mentioned above.
6. GuzzleHttp\Exception\ServerException: Server error:
Here is another kind of exception that can be thrown by Guzzle. A ServerException
is thrown when HTTP 500 errors are encountered, if the http_errors request option is set to true.
$client = new \GuzzleHttp\Client();
$res = $client->request('GET', 'https://httpbin.org/status/503');
The above example throws the client exception "Server error: GET https://httpbin.org/status/503
resulting in a 503 SERVICE UNAVAILABLE
response", because the service is not available.
The root cause of such errors may be any of the following:
- The format or service you are requesting is temporarily unavailable.
- Your server has received errors from the server you are trying to reach. This is better known as the "Bad Gateway" error.
- The HTTP protocol you are asking for is not supported.
The ServerException
can also be handled by using a try/catch block, as in the example below.
try {
$client->request('GET', 'https://httpbin.org/status/503');
} catch (ServerException $e) {
echo Psr7\str($e->getRequest());
echo Psr7\str($e->getResponse());
}
As in the previous example, which caught a ClientException
, this example will catch any thrown ServerExceptions
that result from the call to $client’s request method.
7. QueryException: SQLSTATE[42S02]: Base table or view not found
The query exception "Base table or view not found" can be thrown when your code attempted to operate on a database table that does not exist, or (for some reason) could not be found. Have a look at the following example.
$user_name="test";
$data=array('user_name'=>$user_name);
DB::table('testtable')->insert($data);
In my case it is throwing "SQLSTATE[42S02]: Base table or view not found: 1146 Table" because we are trying to insert data into a table that does not exist in the database. Make sure the table is present first, to avoid these kinds of exceptions. Alternatively, as in the previous two examples, wrap the call to insert in a try/catch block, which will catch the QueryException
, as in the following example.
$user_name="test";
$data=array('user_name'=>$user_name);
try {
DB::table('testtable')->insert($data);
} catch (QueryException $e) {
printf ("Error occurred: %s\n”, $e->getMessage());
}
8. PDOException: SQLSTATE[HY000] [2002] Connection refused
PDOExceptions
represent errors raised by PDO (PHP Data Objects) which, as the PHP manual describes, are "a lightweight, consistent interface for accessing databases in PHP".
The possible root causes of a "PDOException : Connection refused" may be one of the following:
- You do not have sufficient privileges to access the database or to perform that operation as that user;
- Your database parameters (server name ~ host name and or port number, username, password, database name) are not correct; or
- The server where you have your database is not accessible—it may be offline.
9. BadMethodCallException: Call to undefined method
In PHP, the "BadMethodCallException: Call to undefined method" error occurs when you are trying to call an undefined method of a class. Have a look at the example below.
class Card {
}
var_dump(Card::all());
The above code will throw "BadMethodCallException: Call to undefined method" because we are attempting to call the all
method which does not exist in the Card
class (yet). To avoid this kind of exception make sure the called method is defined in the class. Alternatively, you could implement the __call
magic method to handle calls to undefined methods. However, this approach may get messy.
10. QueryException: SQLSTATE[42000]: Syntax error or access violation
This kind of error occurs when the SQL query you are trying to execute is syntactically incorrect. The below example will throw error "Syntax error or access violation" because the select query statement is syntactically incorrect. In this case, the from
keyword is missing.
$cards = DB::select("SELECT * testtable");
This exception can also occur if the user does not have permission to perform the operation on the database. The example below will throw an error if the user does not have insert privileges.
$user_name="test";
$data=array('user_name'=>$user_name);
DB::table('testtable')->insert($data);
Conclusion
There are several development best practices that can help you avoid encountering these errors in production. The first is to use a good IDE like PhpStorm which can help you use and correct syntax while you are developing. This will help you avoid parse errors from getting to production.
Another best practice is to use unit and integration testing tools, such as PHPUnit, Codeception, Behat, and Selenium. These can help you prevent shipping code to production (assuming you are deploying correctly), that contains errors
Some errors like HTTP server errors are not completely avoidable. However a well-written application will handle them gracefully, such as by catching them and showing an error message to the user.
We hope that you learned something new and are better placed to avoid errors in the future. We also hope that this guide helped you solve a head scratcher that you’ve been struggling with.
It’s important to have visibility into errors that affect your users, and to have good tools to solve them quickly. Rollbar gives you visibility to production PHP errors and gives you more context to solve them quickly. For example, it offers additional debugging features like telemetry and local variable values which make it so much easier to debug.
Learn more in Rollbar’s full list of features for PHP applications.
If you haven’t already, sign up for a 14-day free trial of Rollbar and stop flying blind in production.