Use collection of objects or single object collector

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Use collection of objects or single object collector

Post 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.
User avatar
dbevfat
Forum Contributor
Posts: 126
Joined: Tue Jun 28, 2005 2:47 pm
Location: Ljubljana, Slovenia

Post by dbevfat »

User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post by RobertGonzalez »

So you are saying to use individual objects instead of a single object?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post 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.
(#10850)
User avatar
MrPotatoes
Forum Regular
Posts: 617
Joined: Wed May 24, 2006 6:42 am

Post 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
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post 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).
User avatar
MrPotatoes
Forum Regular
Posts: 617
Joined: Wed May 24, 2006 6:42 am

Post 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++
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post 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...;).
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post 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.
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post 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.
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post by RobertGonzalez »

Thanks all. I appreciate the input.
User avatar
MrPotatoes
Forum Regular
Posts: 617
Joined: Wed May 24, 2006 6:42 am

Post 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
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post 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.
(#10850)
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

See here for some Constructor Injector goodness :)

viewtopic.php?t=55387

[/pimp]
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post 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.
Post Reply