If you've ever done any perl programming, or if you've spent any time talking
to perl programmers, you have probably heard of "CPAN" - the Comprehensive Perl
Archive Network. CPAN provides a central repository of perl modules, most of
which are made available under the same licenses as perl itself (the GPL and
The Artistic License). In many ways, CPAN has been "the killer app" that has
made perl one of the most popular languages around. By using CPAN, a perl
developer can quickly assemble the majority of the code needed for their
programs, leaving them to simply code the glue needed to stick all the modules
together into a cohesive whole.
The PHP Extension and Add-on Repository (PEAR) project is an effort to develop a repository similar to perl's
CPAN and TeX's CTAN for the PHP community. PEAR will offer much more than the
useful, but rather ad-hoc code snippets in the
Code Gallery available on
Zend's web site. By providing an infrastructure and defining a set of
standards that all contributors must adhere to, PEAR, combined with PHP 4, may
be just what is needed to take PHP to the next level.
The intention behind PEAR is to provide a means for library code authors to
share their code with other developers, to give the PHP community an
infrastructure for using third-party code, to define standards that help
developers write code that runs in different PHP configurations, and to provide
tools for code maintenance and distribution.
PEAR Standards
Perhaps the most important part of the PEAR project is finally defining an
official standard for creating reusable, well documented php packages. A
standard set of guidelines are necessary to make sure all PEAR packages are
available to as many developers as possible. Since PEAR is still in
development, the current set of rules and guidelines are subject to
discussion and change. If you take issue with any of these guidelines, or have
a better solution, you should let the developers know by posting to the
PHP-PEAR mailing list.
Naming Guidelines
The extension .php must be used for all files containing php code. A related
set of one or more classes and functions are called a "package". These
packages are organized into the PEAR package structure. The package structure maps
1:1 to the file system, but is based on the argument provided to the "use" or
"import" functions.
Because PHP does not implement name-spaces, class names must be
based on the package they are implemented in. The class name is derived by
simply replacing the slashes in the package name with under scores. Thus, the
package "DB/common" has it's code in the file "DB/common.php", and defines a
class called "DB_common". This strategy should prevent any naming
collisions despite the lack of separate name-spaces.
Functions should be named with underscores separating lowercase words, for
example my_function. Methods should use initial lowercase studly caps, like
myMethod.
Error Handling
The correct way to handle errors is still a subject of discussion on the PHP-PEAR mailing
list. It is important however, that you never call die or
exit inside your packages. Doing so will prevent the application
using your package from handling the error in a more graceful fashion. You
should instead return an error to the caller, even if it is only a boolean
value. One error reporting method proposed by Sterling Hughes is to create a standard PEAR_ERROR
object that is created within your package and then returned to the caller.
<?php
class PEAR_ERROR {
var $errno;
var $errstr;
var $calling_package;
var $method;
}
//You can then use this code to
//return an error from your package.
class fubar {
function foo ($args) {
if (count ($args) < 1) {
$ret = new PEAR_ERROR;
$ret->errno = WRONG_PARAM_COUNT;
$ret->errstr = "Wrong parameter count";
$ret->calling_package = "fubar";
$ret->method = "foo";
return ($ret);
}
}
}
?>
The recent release of PHP 4.0.1 also brought several enhancements to PHP's
built-in error handling capabilities that might prove useful in creating an
error handling solution for PEAR packages.
Optional Feature Dependencies
In order to make sure your PEAR packages can be used by as many PHP developers
as possible, your code should not be dependent on optional features unless it
absolutely needs them.
One example is the magic_quotes_gpc configuration option. Proper PEAR
packages should work with or without this option enabled. Here's an example
that does just that.
<?php
// If magic_quotes_gpc is enabled, remove those slashes.
if (get_cfg_var("magic_quotes_gpc")) {
$arg = stripslashes($arg);
}
?>
Your code should always use the <?php ... ?> syntax, since the
shorter forms <? ... ?> and <% ... %> may be
disabled.
Since the register_globals configuration may be disabled, your code
should make use of the appropriate HTTP_*_VARS global arrays.
Scope Issues
If your package is included from within a function, any variables you define
(outside your package's classes and functions) will inherit the scope of the
calling function. For this reason it is a good practice to define these globals using
the $GLOBALS associative array.
PHPDoc
Many modern languages have a built in documentation system which allows
developers to embed documentation into their code. This makes keeping
documentation up to date easier, and simple tools can be created to parse the
documentation out of the code and create docs in formats such as HTML, XML,
etc. PEAR has adopted
Javadoc
as its official inline documentation format.
Development efforts are currently underway to write javadoc parsers in php, and
provide "phpdoc" tools for php developers.
Writing PEAR Packages
To re-cap, here are the things you need to keep in mind when writing code that
you intend to eventually submit to PEAR.
- Packages should be named based on their functionality.
- Classes have the same name as your package, but with slashes replaced with underscores.
- Files containing php code should have the extension ".php".
- You should never call
die or exit from within your packages.
- Instead, you should return an error to the caller, even if it's just a boolean value.
- You should use
get_cfg_var to determine if certain optional features are enabled.
- You should use the <?php ... ?> code block tag syntax.
- You should use HTTP_*_VARS instead of relying on global variables.
- Global variables should be defined using the $GLOBAL array.
Resources
The following pages were using extensively in the writing of this document.
Special credit must be given to Stig Bakken, who wrote the PEAR documentation
which provided the bulk of the information in this document.