What are the problems PEAR2 seeks to solve? [and a solution to the require_once debacle]
| From: | Gregory Beaver | Date: | Wed, 29 Aug 2007 04:52:36 +0000 |
| Subject: | What are the problems PEAR2 seeks to solve? [and a solution to the require_once debacle] | ||
| Groups: | php.pear.dev | ||
| Request: | Send a blank email to pear-dev+get-47890@lists.php.net to get a copy of this message | ||
PEAR2 is a repository of code that seeks to solve these problems:
1) provide a simpler installation system than PEAR
2) provide code that takes advantage of the best new features in PHP 5
and beyond
3) provide a stronger coding community than PEAR
4) provide more flexible code that can be used in more settings
5) provide better application support
6) provide a more rigorous standard for stable code
7) provide a safer and more relaxed environment in which to innovate
8) pay more conscious attention to performance as part of the goal to
be flexible and attract more developers who will use this code in
high-traffic situations
Specific problems that have arisen recently include:
* inability to easily relocate a PEAR installation
Many people find it difficult to move a PEAR installation to another
location on the same computer, or more importantly, to deploy it to a
production server. There have been regular messages on pear-general
dealing with problems of remotely installing PEAR, whether it is with
PEAR_Frontend_Web on unix, PEAR_RemoteInstaller, or strange bundlings of
PEAR files that break the relative locations of files, requiring odd
include_path hacks.
* difficulty bundling PEAR libraries inside applications not distributed
through the PEAR installer
It is generally more complex to bundle a PEAR library because the
relative includes in require_once force the user to set up a relative
include_path programmatically, and to ensure that there are no files
with the same names (i.e. DB.php, for example) that would be loaded instead.
* difficulty managing multiple PEAR installations
This has been a problem most often when users on unix have a system PEAR
installation and a local installation, or other similar setups where
include_path points at the wrong installation, making it look like
packages have been installed that have not otherwise been installed.
* difficulty managing uncaught PEAR_Error
We've all seen the posts like "I get fatal error: call to unknown method
PEAR_Error->add(), but I asked for a Foo object!"
* great difficulty re-bundling a PEAR package into another non-PEAR format
Some examples: any phar archive, go-pear, installation scripts for web
applications that require PEAR like blogs.
Many people asking for technical support are having trouble
understanding how their application expects them to set up include_path
because it is not immediately apparent where the files should be, or why
the application is not detecting their properly installed PEAR
repository and so on, which is evidence that the web application authors
also had difficulty with this question of re-bundling PEAR or externally
requiring it.
* complications making code based on PEAR opcode-cacheable
This point has been hashed and re-hashed on the mailing lists, and I
don't wish to pick at old scabs if possible, but will clarify if asked
(again).
PEAR2 also seeks to preserve the strengths of PEAR, which include:
1) passionate developers who want a venue to voice their talents
2) strong dependency management
3) strong stability (stable/beta/alpha) management
4) a clear, unified coding standard
5) easily debugged code with clear documentation of inter-file dependencies
With these problems and goals in mind, the RFC was born. Several
exciting changes have happened in the core of PHP itself that will
directly influence the final decisions of what PEAR2 and its installer
Pyrus will look like. The first genesis of the RFC occurred after
several high-profile blog posts of Rasmus, Gopal and a few others that
all reviled the usage of require_once/include_once as a performance
killer and enemy of the KISS principle in PHP. Rasmus's post was the
un-framework PHP framework (which incidentally recommends writing the
framework yourself primarily, rather than using re-usable components,
but I think we can prove that sentiment to be misguided with time :).
Gopal posted several entries on his struggles getting APC to cache
require_once/include_once and some of the misguided attempts to
circumvent include_once.
After reading these, I posted a message to pear-group
(http://osdir.com/ml/php.pear.core/2006-10/msg00018.html) which I
excerpt here:
"...a list of my priorities for the next generation installer.
#1 installer should run out of the box without needing installation
#2 libraries need to be opcode cache-friendly (require instead of
require_once, or a class loader)
#3 simpler configuration
#4 better registry
Only #2 affects the PEAR community at large, although as you'll see #3
could have a significant impact."
I've already implemented #3 and #4, and in part of the effort to implement #1, discovered a few
of the other aspects of the RFC. #2 shows my initial thoughts. After several people including
Rasmus volunteered opinions, one of which in particular was very influential
(http://osdir.com/ml/php.pear.core/2006-10/msg00020.html), and his reply here
(http://osdir.com/ml/php.pear.core/2006-10/msg00027.html) to my next attempt. Watching the
evolution of the original idea, which can be summed up as "class loader, maybe __autoload() or
something?" to the last message should make some more sense seeing it.
Once the idea of using autoload() or not was settled, only then did it occur to me that this would
solve the problem of bundling a package into a phar archive and glomming a packaging into a single
file was suggested much later by a developer (sorry, don't remember who). As such, these are
ancillary benefits. The primary goal is to make PEAR2 just as easy to work with but more efficient
than PEAR on the systemic level. It will still be up to the individual authors to make their code
run as fast as it can, and PEAR2 as a repository won't seek to control that, it will be up to
developers and their collectives to do so. However, removing an obvious barrier that can make a
difference is worth doing IF it doesn't compromise the other goals.
The addition of the "allfiles" idea was simply an attempt to help beginners load a package
all at once without needing to do any configuration whatsoever - this is the sole goal of the
"allfiles idea" and as can be seen, this simple idea ends up being very complex in
practice.
My best experiences working with PHP apps and libraries have been the ones that have needed the
least configuration, and have both made good assumptions for me, and offered few options. One of
the primary goals of PEAR2 is to capture this experience for PEAR packages. This is why the idea of
removing php_dir and data_dir as configurable values is so appealing - it removes the need for
either php_dir or data_dir replacements in most situations, simplifying both the packaging process
and the installation process, and thereby cutting down on errors.
It must be noted that the addition of namespaces changes a great deal. There is an uncommitted
patch on php-internals adding autoload support to namespaces which will change things quite a bit.
Because of that patch, using unqualified classnames no longer works with autoload if they share the
same name as an internal class (like Exception), which will happen with this code:
PEAR2/Package/Exception.php:
<?php
namespace PEAR2::Package;
class Exception extends PEAR2::Exception {}
?>
PEAR2/Package/Thing.php:
<?php
namespace PEAR2::Package;
class Thing
{
function __construct()
{
// this should load PEAR2::Package::Exception, but instead throws the built-in Exception
throw new Exception('hi');
}
}
?>
However, by using an explicit import, the problem goes away:
PEAR2/Package/Thing.php:
<?php
namespace PEAR2::Package;
import PEAR2::Package::Exception; // from PEAR2/Package/Exception.php
class Thing
{
function __construct()
{
// this now loads PEAR2::Package::Exception
throw new Exception('hi');
}
}
?>
Suddenly, this doesn't look so different from:
PEAR2/Package/Thing.php:
<?php
namespace PEAR2::Package;
require_once 'PEAR2/Package/Exception.php';
class Thing
{
function __construct()
{
// this should load PEAR2::Package::Exception, but instead throws the built-in Exception
throw new Exception('hi');
}
}
?>
So perhaps by substituting the import statement for require_once, this will preserve the readability
and maintainability? It should be noted that for conflicting classnames, we can also use:
import PEAR2::OtherPackage::Exception as OException;
and then use it freely in the file as "OException"
I hope this document will help to settle some of the bad blood that has occurred on pear-dev. I,
and the entire PEAR Group, wish to apologize for any appearance of strong-arming, and hope that with
this message, the motives, the problems, and some of the potential solutions are better understood.
Thanks for your time and reading all the way to here.
Greg