Re: Re: PEAR2 Coding standards, Autoloading and Namespaces

From: Date: Sun, 06 Apr 2008 13:26:31 +0000
Subject: Re: Re: PEAR2 Coding standards, Autoloading and Namespaces
References: 1 2 3 4 5  Groups: php.pear.dev 
Request: Send a blank email to pear-dev+get-49667@lists.php.net to get a copy of this message
Jeff Moore wrote:
On Apr 4, 2008, at 5:28 AM, Greg Beaver wrote:
Seriously, though, the logic it takes to think in terms of packages and the classes within a package do not apply here because java distributes packages as a language feature, and enforces class naming. This requires a level of WTF that is unnecessary for PEAR. Packages are an abstract entity that are used only when downloading. The class names are what will be used on a daily basis, and I strongly encourage us to think in those terms. Which are you more likely to find natural to use, PEAR2::HTTP::Request, or PEAR2::HTTP_Request::Request? If I saw the latter classname, I would scratch my head at the redundancy, and expect the class to be in either "PEAR2/HTTP_Request/Request.php" or "PEAR2/HTTP/Request/Request.php". Both of these are confusing at best, and obfuscate the actual location at worst.
So mapping package names to namespaces is a non-goal? I'm not sure the advantages of one way or the other are clear-cut. Consider two ways to organize a hypothetical package, Foo that contains two classes, Foo and Bar: EXAMPLE 1: Namesake class Foo outside the Foo namespace... PEAR2/Foo.php: namespace PEAR2; class Foo {
    function hello() {
        echo "Hello!\n";
    }
} PEAR2/Foo/Bar.php: namespace PEAR2::Foo; class Bar {
    function baz() {
        $obj = new PEAR2::Foo();
        $obj->hello();
    }
} index.php: // Setup autoloader $obj = new PEAR2::Foo(); $obj->hello(); $obj = new PEAR2::Foo::Bar(); $obj->baz(); Pro: * External code can use a short and natural reference [PEAR2::Foo] to refer to the Foo class. Con: * Foo.php is not in the Foo directory (confusing, bad for version control) this is incorrect, my previous message discussed this point.
* The Bar class must refer to Foo with the fully qualified name, new PEAR2::Foo(). Also incorrect. One can easily do "use PEAR2::Foo;" and then use "new Foo"
* The Foo class must use the fully qualified name to reference classes inside the PEAR2::Foo namespace (not illustrated here). Also incorrect for the same reason as above.
* The relationship between Foo and Foo::Bar is not clear to automated tools (such as phpDocumentor). Also incorrect, phpDocumentor doesn't even care or know about namespace as this is not an enforced relationship the way a java package is. Because phpDocumentor (and other tools) are general purpose PHP tools, they can't make any assumption about package, and use @package tags to make these associations explicit. Using namespace would not be difficult, and one could even use prefix (i.e. anything that is PEAR2::Foo*) quite easily, as the actual implementation of namespaces simply stores classnames as strings, with no explicit namespace information.
EXAMPLE 2: Namesake class Foo inside the Foo namespace... PEAR2/Foo/Foo.php: namespace PEAR2::Foo; class Foo {
    function hello() {
        echo "Hello!\n";
    }
} PEAR2/Foo/Bar.php: namespace PEAR2::Foo; class Bar {
    function baz() {
        $obj = new Foo();
        $obj->hello();
    }
} index.php: // Setup autoloader $obj = new PEAR2::Foo::Foo(); $obj->hello(); $obj = new PEAR2::Foo::Bar(); $obj->baz(); Pro: * Code within the namespace can access the Foo class without fully specifying the class name, new Foo(). this is no different from above as per my first point.
* Foo can access other classes in the same namespace without fully specifying the class name (not illustrated here). this is no different from above as per my first point.
* All the files in the Foo namespace are in the same directory. the only actual difference, but I have a killer to it (see below)
* The relationship between the two classes is structurally clear for automated tools. this is no different from above as per my first point.
Cons: * Exactly one class in the namespace, the namesake class, must be referenced outside of the package by the distasteful name, PEAR2::Foo::Foo. OK, let's assume we do put packages always within the directory. How do we handle subpackages or external helper packages? For instance, database packages have drivers. Your proposal would have a different file naming standard for subpackages from regular packages.
Let's think of another example: the PEAR package and the PEAR_PackageFileManager package. These are not subpackages, but are related. Currently PEAR's files go into PEAR/ and PEAR_PackageFileManager class go into PEAR/PackageFileManager. Would you suggest the classname for a similar class be PEAR2::Pyrus_PackageFileManager::PackageFileManager or PEAR2::Pyrus::PackageFileManager::PackageFileManager? Very quickly, we start running into 100 character classnames all for a non-issue of trying to make the directory appearance feel cleaner at the expense of code clarity and package=>classname mapping clarity. PEAR users are very used to the idea that the PEAR_PackageFileManager package results in a class named PEAR_PackageFileManager in PEAR/PackageFileManager.php, and it has worked great since 1999 with no complaints since I joined PEAR in 2002. I don't see a problem to be fixed here. As already noted, none of the objections you've raised are truly problems for various technical reasons (source repository already separates by directory, the use statement solves the others, automated tools for PHP at large can't depend on any organizing principle beyond what is hard-coded into the language). If you all feel strongly about changing this issue even after my strong objections, I suggest you follow the official path and propose an RFC to the PEAR Group for changes to the PEAR2 coding standards (which are up for review, by the way). Thanks, Greg

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