Page 1 of 2

Use collection of objects or single object collector

Posted: Fri Oct 20, 2006 1:23 pm
by RobertGonzalez
Ok, so I have this project that I am putting together. I have build several classes that are meant to handle most of the apps work. As of now I have an error class, page class, mysql class, sybase class, template class, sessions class and config class. So I am now wondering...

Should I use individual objects for each of these throughout the app, or should I make a collection object that implements these objects applications wide?

This...

Code: Select all

<?php
$error = new Error();
$page = new Page();
$mysql = new MySQL_Class();
// ...
?>
or this...

Code: Select all

<?php
Class Application
{
    public $error;
    public $page
    // ...
    public function __construct()
    {
        $this->error = new Error();
        $this->page = new Page();
        // etc, etc
    }
}
?>
I am now leaning toward one object that invokes them all and floating that opbject around. But I am not sure what the potential ramifications are of this. Any ideas or suggestions would be most appreciated.

Posted: Fri Oct 20, 2006 1:52 pm
by dbevfat

Posted: Fri Oct 20, 2006 2:30 pm
by RobertGonzalez
So you are saying to use individual objects instead of a single object?

Posted: Fri Oct 20, 2006 3:00 pm
by Christopher
You might want to read Fowler's article about Dependency Injection because you now have the need. Implementing a Registry is the current state-of-the-art in PHP. It gives you access to these objects that you need, when you need them. But it provides a clear interface. And because it is injected the whole thing is testable/mockable. Service Locator is a next step but probably not necessary in your case as the classes you listed are generics.

Posted: Fri Oct 20, 2006 3:19 pm
by MrPotatoes
i have what you call a registry within my system and i didn't even know what it was. what's even more hilairous is that my code is almost exactly the same as that code in the first link

Posted: Fri Oct 20, 2006 3:36 pm
by RobertGonzalez
What about using a Factory? It seems that would be most appropriate for initializing the objects. Or am I way off? This is my first dive into the deep waters of Design Patterns (in practice).

Posted: Fri Oct 20, 2006 3:45 pm
by MrPotatoes
i guess mine is a mix of factory and registry. see what i do is i do what the registry does but i intantiate it within the function

you give it the name of the class you want to instantiate and it searches through the correct folders and then finds that class and instantiates it.

that's what i do

Code: Select all

private $loader = array();

public function __construct() 
{
	$loader = null;
}

public function CreateInstanceOfLibrary($_library)
{
	if (is_object($this->library[$_library]))
		exit('whoops');
	require_once(LIBRARY_PATH . $_library . '.lib.php');
	$this->loader[$_library] = new $library;
}

public function CreateInstanceOfOtherClass($_class)
{
	if (is_object($this->library[$_class]))
		exit('whoops');
	require_once(CLASS_PATH . $_class . '.class.php');
	$this->loader[$_class] = new $class;
}
don't quote me. i'm not actually looking at my code. this is pusedo but this makes me one instance full of instances :). i figured this was the next best thing since i couldn't use vectors/Linked lists likei could in C++

Posted: Fri Oct 20, 2006 4:46 pm
by Maugrim_The_Reaper
What about using a Factory? It seems that would be most appropriate for initializing the objects. Or am I way off? This is my first dive into the deep waters of Design Patterns
A few things to keep in mind. A key goal often found in a design pattern implementation is to reduce dependency. In your initial example, your Application class has three dependencies and growing. It really seems like you are finding your way towards a Registry. A Registry put in simplest terms is a basket - you can store objects in it and grab one when required.

In your original post I would have a Registry object (follow the link for the code) and in one of my bootstrap files

Code: Select all

$error = new Error();
$page = new Page();
$mysql = new MySQL_Class(); 

$registry = new My_Registry;
$registry->register('error', $error);
$registry->register('page', $page);
$registry->register('mysql', $mysql);

// or condense the above into the form

$registry = new My_Registry;
$registry->register('error', new Error);

// etc.
A Registry is a basic idea - don't take the example implementation as the end of the line. Zend Framework implements a Registry as static methods on the base Zend class, for example. It boils down to the same functionality, just with a varying interface. I believe that's been refactored into a dedicated Zend_Registry soon...

A Factory Pattern differs since it does not replace a Registry. Both are independent Patterns with separate uses. Where a Registry stores objects (or any value by the way) in a single parcel (easy to pass as parameter, or as a Singleton, or with static methods), a Factory is useful when creating an object requires a series of steps beyond a simple new Class(); statement. A fair example is where the decision on which one of a varying family of classes with identical API's requires some logic. For example, deciding whether to use Mysql_Class, Mysqli_Class, Postgres_Class, Sybase_Class, etc. It's usually a single Factory method on another class, or can be a standalone class itself. It's usually only useful where decision or initialisation logic exists which would be duplicated across the application unless centralised in a Factory. It's usually good practice to avoid Factories unless you're certain it's needed.

As an example, you could use a Factory to determine which Database class to initialise, and register the resulting object to a Registry. Both being used in concert...;).

Posted: Fri Oct 20, 2006 5:13 pm
by RobertGonzalez
Ok, I get the idea of the Registry, but how do you utilize your objects throughout the app? Say I do this...

Code: Select all

<?php
$registry = new My_Registry;
$registry->register('error', new Error);
$registry->register('pager', new Pager);
$registry->register('mysql', new MySQL_Class);
?>
Do I then use the registry to call the methods of a given class? That seems a little confusing to me.

Posted: Fri Oct 20, 2006 5:25 pm
by Maugrim_The_Reaper
From within a class you would:

Code: Select all

// if using a Singleton Registry...

$registry = My_Registry::getInstance();
$mysql = $registry->get('mysql');

// if using a Static Method Registry

$mysql = My_Registry::get('mysql');

// or you could pass it as a parameter to a class constructor
// and set it as a property

$mysql = $this->registry->get('mysql');
In all cases, the class does not instantiate any of the objects. It does not know the class names. All it knows is that the Registry has some object with the Registry key "mysql" which follows a certain interface. You could name the key "database" assuming it could be any of a few options - the class using the Registry doesn't care so long as the object with key "database" follows the expected interface.

Posted: Fri Oct 20, 2006 5:38 pm
by RobertGonzalez
Thanks all. I appreciate the input.

Posted: Fri Oct 20, 2006 6:08 pm
by MrPotatoes
oh. using mine it's a little uglier

Code: Select all

$loadObj->loader[$object_You_Instantiated_Earlier]->Function('params');
lmao, so basically i make an alias for it. i might end up looking at that factory/registry thing. might clean it up some and remove the over head of the alias

Posted: Fri Oct 20, 2006 7:37 pm
by Christopher
Or with controllers you can pass the Registry object directly to the Action methods. That is often the simplest. The is becomes an application context of sorts, but a flexible one.

Posted: Sat Oct 21, 2006 1:04 pm
by Jenk
See here for some Constructor Injector goodness :)

viewtopic.php?t=55387

[/pimp]

Posted: Sat Oct 21, 2006 8:38 pm
by RobertGonzalez
This thread is teaching me soooo much. I came yesterday and immediately started reading Jason Sweats book and Matt Zandstra's book on the Registry and Factory patterns. I think that I may have been making my objects to global by using singleton methodology, but I think that I can still capture that style while still keeping things extensible.

Just as an FYI, this apllication will never move beyond its server and will never be extended outside the app. So I may be making more of the pattern design that I need to. We'll see on Monday.