Re: Re: PEAR2 Coding standards, Autoloading and Namespaces

From: Date: Sat, 12 Apr 2008 22:33:28 +0000
Subject: Re: Re: PEAR2 Coding standards, Autoloading and Namespaces
References: 1 2 3 4 5 6 7 8 9  Groups: php.pear.dev 
Request: Send a blank email to pear-dev+get-49779@lists.php.net to get a copy of this message
On Sat, Apr 12, 2008 at 10:14 PM, Jeff Moore <jeff@procata.com> wrote: > > On Apr 8, 2008, at 1:56 AM, Christian Weiske wrote: > > > > I'd like to think outside the box, if you could tell me the solution > > for following problem: > > - Package MDB3 > > - Driver packages MDB3_Sqlite, MDB3_MySql etc > > > > How do you load those drivers? Currently it was as easy as checking the > > existence of $path/MDB2/Driver/Sqlite.php and include the file with > > that name. > > If every package uses his own namespace, how do you load such a driver? > > Where do you store it in the file system so that it can be easily found? > > > > Making exceptions to the packagename->namespace rule would work, but > > defeat the purpose of the whole idea. > > > > Well, I have an answer and its somewhat out of the box, too. :) > > Rather than having a function that "loads" a driver based that driver being > in a specific directory (or based on a specific class name), you can use > dependency injection to pass the plugin into the class that will use it. > > > Driver Pattern: > > class Cache { > static function getCache($driver, $options = array()) { > $file = '/drivers/' . $driver . '.php'; > require_once $file; > $classname = ucfirst($driver) . 'Cache'; > return new $classname($options); > } > } > > class CacheDriverCommon { > protected $options; > function __construct($options) { > $this->options = $options; > } > } > > class FileCache extends CacheDriverCommon {} > > class FeedFetcher { > protected $cache; > function __construct($options = array()) { > $this->cache = Cache::getCache( > $options['driver'], > $options); > } > > // Do something with $this->cache later > } > > $fetcher = new FeedFetcher(array('cache'=>'file', > 'cache_path'=>'/tmp')); > > > With Dependency Injection: > > > interface Cache { > // ... > } > > class FileCache implements Cache { > protected $path; > function __construct($path) { > $this->path = $path; > } > } > > class FeedFetcher { > protected $cache; > function __construct(Cache $cache) { > $this->cache = $cache; > } > } > > $fetcher = new FeedFetcher(new FileCache('/tmp');); > > The DI version is more modular, more testable (easier to pass a mock > object), and getting rid of the options array has some advantages, such as > being easier to document, and autocompletion advice in IDEs becomes > available for constructor parameters. You didn't really answer the namespace issue; All this new Foobar() sounds really cute until you have long class names $oRestoReview = Foo_Content::createType('RestaurantReview') ->addAttribute(new Foo_Attribute( array('name' => 'dateEaten', 'typeId' => FOO_CONTENT_ATTR_TYPE_DATE))) ->addAttribute(new Foo_Attribute( array('name' => 'dishName', 'typeId' => FOO_CONTENT_ATTR_TYPE_TEXT))) ->addAttribute(new Foo_Attribute( array('name' => 'overallRating', 'typeId' => FOO_CONTENT_ATTR_TYPE_FLOAT))) ->save(); This is an example from a real codebase taking this fun approach, start becoming messy soon, don't it ? I'll agree that DI has some benefits over factory pattern; Just two ways of solving this problem, somehow feels like we are effectively excluding factory to a certain extent with this change while the old approach would have supported both ways, at least should have but I might be farting around at this point. - Helgi

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