Why change require_once? A brief explanation of motives
| From: | Greg Beaver | Date: | Tue, 17 Jul 2007 01:07:11 +0000 |
| Subject: | Why change require_once? A brief explanation of motives | ||
| Groups: | php.pear.dev | ||
| Request: | Send a blank email to pear-dev+get-47533@lists.php.net to get a copy of this message | ||
Hi all,
I've been barely following the tremendously long thread on the proposed
coding standard changes. Needless to say, I wish that people would
approach these from a perspective of assuming goodwill from the PEAR
Group and the PEAR president, but I do understand that this is a
difficult assumption to make, as one should be suspicious of anyone in
power for good reasons.
I have extremely limited time to explain where these ideas come from,
but let's just say that they come from many long hours and many long
months of careful research. First of all, anyone wishing to know what
is planned for Pyrus, the installer for PEAR2 should check two
locations, the source code at http://svn.pear.php.net and the
roadmap at
http://pear.php.net/bugs/roadmap.php?package=PEAR
Here is a short list of things that are REALLY important to understand:
1) EVERY existing PEAR package will continue to both install and work,
but packages that use PEAR_Config or PEAR_Registry directly will not
function properly. Replacements will continue to work, nothing is
changing here. (P.S. haven't you all learned by now I'm a BC freak?)
2) The suggested changes to usage of require_once in PEAR packages are a
radical new idea and do require rational and careful evalution. I must
say I am extremely dissapointed with the response so far. I have to
encourage every person who has posted FUD without any investigation to
in the future please try to back up any posted information with facts,
or at the very least links to messages from the archives. Most
installer-related conversation is on the pear-core@lists.php.net mailing
list, and I have been discussing these changes there for over a year now.
As benchmarks have shown, and both Gopal and Rasmus have blogged about,
require_once is a major problem for APC and other optimization systems
because it forces several stat calls. require_once with relative path
makes this even more difficult. On FreeBSD, for instance, stat is a
very expensive system call, and can result in being a more significant
bottleneck for PHP applications than database access. Gopal has blogged
extensively about APC and require_once at
http://t3.dotgnu.info/blog/php/. In addition, one of
the huge problems
APC has encountered is with HTML_QuickForm's require_once "loops" where
drivers require_once the base class, and everything is loaded later,
requiring incredibly complex logic to resolve caching of class
declarations at compile-time. This is not to single out HTML_QuickForm,
but instead to note that may PEAR packages are in fact the source of an
unnecessary complexity that makes it almost impossible to use an opcode
cache to improve the efficiency.
In addition, the use of require_once automatically limits PEAR packages
to use on disk. phar archives are required to modify the source in
order to use the package, resulting in a significant possibility of
accidental error introduction when post-processing the source.
Finally, setting up include_path has proven again and again to be a
major issue, and not just for beginners, as has been asserted in many
(rather condescending) emails written in response. I don't think many
would consider me to be a beginner, but I regularly run into
include_path issues with my development on the PEAR installer. Many
times, the installer finds itself accidentally including an older
version of PEAR simply because the include_path is set up incorrectly.
The same issue has affected my usage of Chiara_PEAR_Server and many many
other scenarios. include_path is not a bad thing, I happen to love it,
but that doesn't mean I always want to rely upon it. Sometimes, when
setting up a "do-this-today" application, I'd rather prototype something
that "just works" and then later properly set up an include_path
environment, something that is physically impossible with the current
PEAR library design.
The new coding standards are designed to eliminate these problems all at
once. There are two separate approaches to this:
Thing 1
=======
Eliminate require_once
1) use class names without loading the files containing them
2) provide an autoload mechanism (PEAR2_Autoload)
3) provide a "it just works" file that can be included to quickly use a
package (allfiles.php)
Thing 2
=======
Better document what is needed
1) use a graceful if (!class_exists('name', true)) for reporting missing
dependencies
2) make sure all files needed are listed in the comments at the top of
each file
3) add a README file to each package
Thing 2 is probably best done as a recommendation, although #2 (document
dependencies) is a must-have.
Note that every PHP user is used to their own pet project's methods, i.e.:
require_once 'Relative/Path.php';
require_once SOME_CONSTANT . 'Relative/Path.php';
Slow_Loader::Load('Classname');
As many benchmarks have shown, all of these are slower than the simple
approach the standards recommend. More importantly, they are
inflexible. The most common complaints about PEAR are (in order)
1) you have to install things
2) you have to set up include_path
3) there's base classes required that are all non-PHP things (PEAR and
PEAR_Error)
4) bloat
To eliminate #1, I have provided several things in the installer, but
they do require that libraries make changes to the way things work like
eliminating replacements.
For #2, The require_once requirement has to go.
#3 means we are never going to have another base class named PEAR2 or
PEAR2_Loader - the inflexibility will make embedding PEAR2 libraries
harder than it is to embed PEAR libraries now.
Finally, #4 means we have to allow people to selectively include
portions of a package, which the proposed solution does in fact allow.
What is really involved for you all? Change you code like so:
<?php
require_once 'Another/Class.php';
class Blah extends Another_Class
{
}
?>
to this:
<?php
/**
* This needs the Another_Class package, located at
http://pear.php.net/pear2/Another_Class
*/
class Blah extends Another_Class
{
}
?>
note that I made up the URL, I have no idea what it will actually look
like for PEAR2.
Users would simply need to either use allfiles.php, autoload, or if
performance is an issue, they can do:
<?php
require '/full/path/to/Another/Class.php';
require '/full/path/to/Blah.php';
?>
and they are good to go, and can turn off APC stat and have efficiency -
ALL interested parties win, use of PEAR skyrockets, and we get a
crapload of new developers in the process to improve things.
I am happy to discuss any of the proposals and change them, but please
limit your comments to brief and carefully researched comments, FUD is
extremely discouraging and does not help us solve the problems at hand.
Thanks,
Greg