Writing an error-resistant PHP-code
Foreword
Errors are curse of every program. The larger a project is the difficult it is to find and correct mistakes. But the most important in working with program are skills of a programmer and his desire to write correct and accurate code containing minimal errors quantity.
In this article I’ll try to collect techniques and methods enabling minimizing errors quantity within a program written in PHP. But some of the methods presented may be useful for you if you write in any programming language.
Knowledge is half of success
PHP informs
In any language there are many potentially dangerous situations which may result into implicit errors. By analyzing with translator the source of a program it may inform a developer about these situations. For this you need only to select a corresponding function which is often switched off on default on some reasons.
Within PHP translator messages output control is determined by function error_reporting and meaning of directive error_reporting in php.ini. It’s recommended meaning is E_ALL i.e. output of messages about all the situations that represent potential danger. For example, in PHP such situations imply usage of a non-initialized variable, addressing a non-existing massive element and so on.
For the maximally detailed translator messages output make a call of function error_reporting at the beginning of the program:
// For PHP4
error_reporting(E_ALL);
or put error_reporting = E_ALL meaning in php.ini.
You may study the more detailed description of possible reporting levels in the PHP-documentation - Error Handling and Logging Functions.
For PHP5 level E_STRICT is introduced which includes output of the messages about out-of-date programming methods usage in the code (when, for example, ‘var’ is used for inner class variables description). It isn’t included in E_ALL and so the message level recommended for PHP5 is E_ALL | E_STRICT (i.e. E_ALL and E_STRICT). Correspondingly to set up output of all translator messages you need to call error_reporting with such parameter:
// For PHP5
error_reporting(E_ALL | E_STRICT);
If it doesn’t report anything
If you’ve set up errors output and the errors aren’t put out nevertheless, the errors output into script output can be probably switched off. Check function’s ini of the file display_errors value (this option switches on direct errors output into script output) and switch it on if necessary.
if (ini_get('display_errors') != 1) { // checks option’s display_errors meaning
ini_set('display_errors', 1); // switches on errors output together with the result of script’s work }
If it reports something
We seldom succeed in complete testing of a program before its release and evading showing error messages to a user as far as we cannot foresee his reaction on them. It’s better to redirect translator’s errors which occurred directly during program working into errors log-file. You can switch on this redirection with option log_errors within file php.ini.
It’s also useful to install your own errors handler if you want not only entry errors into log-file but add some optional logic for their treatment as well. For example, if you want to send a letter by translator message or put out some special message for a user.
We compare a constant with a variable, not conversely
How many times have you found out that an error within a program is caused by usage of operator "=" instead of "=="? To do it more seldom you should use comparisons like
if (10 == $i) {
// we do something
}
In case of usage "=" instead of "==" translator shows up following: "Parse error: parse error in ... on line ...". Thus an error will be discovered considerably faster.
We don’t use a value twice
Of course, it’s an exaggeration. But if the necessity of repeated value usage in a program appears, we can recommend declaring a constant and using it instead of value.
There is one way of constant declaring for PHP4 – it is define function usage.
For example:
define ('BEFORE_RENDER', 'beforeRender');
A constant cannot be declared within classes.
PHP5-extension for constants declaring is similar to that realized by extension from C to C++ - the key word ‘const’ is used. But this way you may create constants within classes only.
For example:
class ControlEvents {
const BEFORE_RENDER = 'beforeRender';
}
print ControlEvents::BEFORE_RENDER;
But you need to know the name of the class for addressing such a constant.
Constants can also be added directly into class. But PHP doesn’t support such a method. Thus you are to declare them as ordinary variables:
class Control {
var $BEFORE_RENDER = 'beforeRender';
function render() {
$eventFunction = $this->BEFORE_RENDER;
$this->$eventFunction();
}
}
Function parameters’ assertion
In PHP you can transmit any variable into function with a parameter. But it can make a difference for the function’s algorithm which variable you’ve transmitted to it. And so it’s useful to check at the beginning of a function its in parameters against the necessary type and value range.
For the type checking following functions are used:
- gettype(Mixed $var) returns type of a variable. The mostly used types are: "boolean", "integer", "double", "string", "array", "object", "resource", "NULL".
- Functions for checking against type: is_bool(Mixed $var), is_integer(Mixed $var), is_double(Mixed $var), is_string(Mixed $var), is_array(Mixed $var), is_object(Mixed $var), is_resource(Mixed$var) – return true or false.
- For object class definition following functions are used:
- get_class(Object $obj) – returns name of a class which specimen obj is.
- is_a(Object $obj, String $class) – checks if obj is a specimen of ‘class’ or of another class which has been inherited from it.
There is no authomatical method of function parameters assertion. All the necessary assertions you have to do on your own.
Code of a function checking arguments can look like this:
/**
* Function showControl accepts one parameter $control,
* this parameter should be a class and
* a specimen of class HTMLControl or class
* inherited from HTMLControl.
*/
function showControl(&$control) {
is_a($control, 'HTMLControl') or $control == null or exit('Type missmatch.');
...
}
The advantage of this method is that you can manage error messages and use your own error handler. For example, you may use following functions for parameters’ checking:
function checkParameter(&$var, $class) {
if (!is_a($var, $class) && $var != null)
SFExit('Type missmatch.');
}
function SFExit(&$message) {
print $message . '<br>';
$backtrace = debug_backtrace();
for($i = 0; $i < count($backtrace); $i++) {
print $i . ': ' . $backtrace[$i]['file'] . '(' . $backtrace[$i]['line'] . ')<br>';
}
exit();
}
Notice: Function debug_backtrace is introduced only in PHP 4.3.0.
Example of their usage:
function showControl(&$control) {
checkParameter($control, 'HTMLControl');
...
}
For PHP5 it’s possible to set up some parameters type’s assertions directly in the description of a function. The previous example in PHP5 will look like this:
function showControl(HTMLControl $control) {
...
}
Asserts
During creation and checkout of a program you may use an integrated mechanism for assertions adding into the code of a program. It is called ‘asserts’. The idea is following: special testing constructions which can be switched off for production site but at the same time switched on by development are included into the program code.
The following code’s parts are nearly the same:
/* Asserts usage*/
assert_options (ASSERT_ACTIVE, 1);
function showControl(&$control) {
assert('is_a($var, 'HTMLControl') || $var == null');
...
}
/* Usage of if-constructions */
define('ASSERT_ACTIVE', 1);
function showControl(&$control) {
if (ASSERT_ACTIVE && !(is_a($var, 'HTMLControl') || $var == null'))
trigger_error('Assertion failed', E_USER_ERROR);
...
}
By means of such assertions you can also check functions’ parameters returned by value functions and so on. You need only to take into account that assertions shouldn’t be switched on in the really functioning site – if the program functions properly and passes all the assertions, they can be switched off.
Check script’s parameters values $_REQUEST, $_GET, $_POST, $_COOKIES.
PHP-script can be treated as a big function which is called with non-defined of string-elements. If you suppose that some parameters will be used in some calculations, they must be converted into the type demanded and use only after evident reduction!
All the REQUEST-massives are ordinary massives and so values within them can be redirected directly.
For example:
if (isset($_GET['id']))
$_GET['id'] = (int)$_GET['id'];
else
$_GET['id'] = null;
Separate and dominate
This principle, well-known since the times of Ancient Rome, can be useful by program development in any programming language and in PHP as well. For realization of this principle divide program into logical blocks. For this you may use following methods:
- Functions’ usage. Separate structure parts of algorithm into functions. Check each part separately and than work of an algorithm as whole.
- Usage of classes. Organize your program code as interacting objects. Extract substances and from them into objects. Carefully examine their interaction. Use the best design patterns where necessary.
- Separate logic and HTML. There are many ways for this: template libraries, XML, XML/XSL. Choose the best one for you and use it.
- Separate the application logic itself by means of enterprise design patterns. Use layering of an application and other technologies enabling structural division of a project into big blocks.
Conclusion
Perhaps the stuff of this article will seem to someone to be a collection of common truths. But I think it will be useful for the most of you and unit “Separate and dominate” can help beginners a lot as far as it sets the direction of programming learning.



