What are the problems PEAR2 seeks to solve? [and a solution to the require_once debacle]

From: 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

« previous php.pear.dev (#47890) next »