| 
	
 | 
 Posted by Kevin Newman on 11/29/05 00:59 
The primary problem I've had with php is the lack of namespaces, which  
makes OOP very difficult to organize, since you end up with large number  
of classes cluttering up the same namespace - which leads to a secondary  
problem involving php's __autoload feature. Since you cannot specify a  
namespace when calling a class that may not have been included, you are  
forced to store all of your classes in the same folder in your file  
system. This can get quite unwieldy. I've also read that __autoload has  
a performance hit over using a standard include (I'm not sure if this is  
still true). Finally, I've read that require_once can be very buggy in  
the php documentation comments. (Is that true?) 
 
After thinking about the namespace problem, I've concluded that php's  
conditional include nature keeps the runtime environment pretty clean  
(if I have two classes with the same name, I don't usually have to worry  
about it, since I will usually only include one at a time) and its  
runtime footprint small. While it's not perfect, it does provide enough  
of something like runtime namespace protection, at least enough to keep  
me from creating a bulky framework to emulate more robust namespaces. 
 
This left me with the problem of organizing all of my class files on the  
file system. I do not want to keep 100s of classes in the same one  
folder - especially since there are many classes in there that will  
probably not be used, but I'd like to keep around for just in cases.  
Since __autoload seems to have performance issues, I decided not to use  
that either. (Is this still an issue?) 
 
Since I've decided that for my needs php's include functions are a good  
enough substitute for real namespace imports I just needed a way to load  
class files that are organized in a namespaces like folder structure. I  
would have just used require_once, but it has those bugs I mentioned. So  
I came up with a single function that I named "using" (borrowed from  
..NET and Prado - which actually has a pretty spiffy solution to the  
namespace problem that uses __autoload). 
 
Here is the function (it is horribly unoptimized and probably buggy): 
 
$namespaces = array(); 
$classPath = 'C:/Inetpub/wwwroot/_domains/adcecart/_includes/'; 
/** 
  * Includes class files, which are stored in Namespace like folders 
  * @param	string	colon delimited namespace string. 
  */ 
function using($namespace) { 
    global $namespaces, $classPath; 
 
    // quick return if repeat import 
    if(isset($namespaces[$namespace])) return; 
 
    // convert $namespace to path 
    $path = $classPath . str_replace(':','/',$namespace); 
 
    if (is_dir($path)) { 
       // add namespace to hash (to avoid double import) 
       $namespaces[$namespace] = $namespace; 
 
       // add all files in the directory 
       $dir = dir($path); 
       while (false !== ($entry = $dir->read()) ) { 
          if (preg_match('/.php$/i', $entry)) { 
             $newNamespace = str_replace('/', 
                ':', substr($namespace.'/'.$entry, 0, -4)); 
 
             if (!isset($namespaces[$newNamespace])) { 
                $namespaces[$newNamespace] = $newNamespace; 
                require_once($path.'/'.$entry); 
             } 
          } 
       } 
       $dir->close(); 
 
    } else if (is_file($path.'.php')) { 
       $namespaces[$namespace]=$namespace; 
       require_once($path.'.php'); 
    } else 
       exit('Error importing namespace.'); 
} 
 
// used like this 
using('unFocus:Feature:ClassName'); 
 
 
This actually does one more thing than a simple enhanced require_once -  
it can import all of the php files in a specific folder (or namespace).  
I don't use this feature, and will probably remove it unless I find some  
need for it. 
 
This function works differently (and I use it differently) than a  
regular namespace implementation would. In other languages, namespace  
imports (or using) are tied to the specific class file scope, and only  
applied to class within that class. As far as I can tell, php has no  
similar scoping rules (since it is an inline interpreter, unless  
something has changed that I am unaware of), so this will just include a  
class file (and anything else that might be in that file actually - like  
spare functions or variables), and dump all that into the global scope  
(except  variables). 
 
This can also be used with performance in mind - let's say you want to  
use a class from another class, and you will only need it if conditions  
are met. You don't have to import the class if you don't need it, saving  
memory, parsing, and cpu time. To me this is a benefit, since php is  
really an inline interpretor at the end of the day (unless you use an  
opcode cache I guess). 
 
At this point really just rambling, so I'll just finish up with a summary. 
 
The goal was to be able to organize and group my class files in some  
kind of reasonable way - namespaces provided that way, but are  
unavailable in php. Understanding the nature of php's inline  
interpretation, conditional includes and __autoload's inability to cope  
with a namespace like directory structure and its possible performance  
consideration convinced me that a simple require_once function used with  
classes named carefully would actually be adequate to make sure I was  
only importing classes that I needed and that they would not clash with  
one another or with built in php classes (I've never run into that  
problem yet). After trying out a bunch of different namespace solutions,  
I wrote a simple function (which can be a lot simpler) that will include  
the necessary class files only once, when they are needed, and not  
before, from within their namespace like directory structure. 
 
Now the question! :-) Basically - What do you think of my reasoning and  
rational? 
 
Also, if I'm wrong about any of the details of how PHP works, I'd  
appreciate some clarification on anything I got wrong. 
 
Thanks, 
 
Kevin N.
 
  
Navigation:
[Reply to this message] 
 |