Page 4 of 4
Posted: Fri Jul 21, 2006 8:42 pm
by Christopher
Here's the list again:
- Be able to register a list of parameters to pass to the constructor (we may need eval() for that) DONE
- Be able to specify that a parameter is another "registered" object that we get() an instance of to pass as a parameter (think of a Model object that need a DB connection object passed to its constructor)
- Allow get() to get objects as singletons or multiple instances
- Allow instances to be accessed by a name that is not the class name. DONE
- Have the class name to file name mapping be configurable when you create the Service Locator (not everyone likes your naming style ) DONE
- Keeping Lazy Loading so that if we never get() the class it is never instansiated (say an error redirect occurs before the get()). DONE
- Make it so it is easy to use as __autoload() or spl_autoload().
- How does PHP5 make our job easier or the interface nicer?
- Do we want to add a settable list of paths that get() will search -- like Todd_Z does as an option?
Posted: Fri Jul 21, 2006 9:00 pm
by Luke
arborint wrote:- Be able to specify that a parameter is another "registered" object that we get() an instance of to pass as a parameter (think of a Model object that need a DB connection object passed to its constructor)
It can do this
arborint wrote:- Allow get() to get objects as singletons or multiple instances
I am working on this... if anybody has any suggestions, please let me know because I am struggling a little
arborint wrote:- Make it so it is easy to use as __autoload() or spl_autoload().
how would I know if it is easy as those?
arborint wrote:- How does PHP5 make our job easier or the interface nicer?
Uhh....
arborint wrote:- Do we want to add a settable list of paths that get() will search -- like Todd_Z does as an option?
Where is this example?
Posted: Fri Jul 21, 2006 9:52 pm
by Christopher
Well where is Todd_Z to say adding this feature is worth doing. I had the comments about it
here. I think that resolving PEAR style class names would be a better addition.
Posted: Sun Jul 23, 2006 3:06 pm
by Luke
For some reason, if you get() from the registry more than once, it throws this error...
Fatal error: Cannot use object of type MysqlConnect as array in c:\wamp\www\module_admin\classes\Registry.inc.php on line 80
Code: Select all
<?php
class Registry{
private $objects;
private $path;
private $prefix;
private $suffix;
function __construct($path='/', $suffix='.inc.php', $prefix='') {
// Path to classes
$this->path = $path;
// Allows for classes to be searched out by a prefix such as ClassSession.inc.php (Where Class is the prefix)
$this->prefix = $prefix;
// Allows for classes to be suffixed and have any allowed extension
$this->suffix = $suffix;
}
private function instantiate($class, $name) {
if(!is_object($name)){
$arglist = array();
if (isset($this->objects[$name]['params'])) { // there are args
$n = count($this->objects[$name]['params']);
for ($i=0; $i<$n; ++$i) {
$arglist[$i] = "\$this->objects['$name']['params'][$i]";
}
}
//ob_start(); // This doesn't prevent jack, does it?
eval ("\$object = new " . "\$class(" . implode(', ', $arglist) . ');');
//ob_end_clean();
// Unset temporary params and class name as they are no longer needed
unset($this->objects[$name]['class']);
unset($this->objects[$name]['params']);
// Store object in registry
$this->objects[$name] = $object;
}
return $object;
}
public function register($class, $name=null /*, $arg1, $arg2... */){
// If object name is not set, object is named the same as it's class
if(is_null($name)) $name = $class;
// Store object's classname and params temporarily (if class hasn't already been registered)
if(!isset($this->objects[$name])){
$params = func_get_args();
array_shift($params); // Remove $name from param list
array_shift($params); // Remove $class from param list
// Register params
$this->objects[$name]['params'] = $params;
$this->objects[$name]['class'] = $class;
}
}
// TODO: Make child classes autoload their parent before instantiation
private function load($class){
if (! class_exists($class)) {
include($this->path . $this->prefix . $class . $this->suffix);
}
}
public function get($name){
// Load the class file
$this->load($this->objects[$name]['class']); // LINE 80
// Instantiate class
$object = $this->instantiate($this->objects[$name]['class'], $name);
// Return object id
return $object;
}
}
?>
Posted: Sun Jul 23, 2006 3:55 pm
by sweatje
It seems odd to me that you use $this->objects[$name] in multiple ways.
Sometimes you are storing $this->objects[$name]['class'] and $this->objects[$name]['params'], but then you later override this and just store an object. Your error is probably from going back later and expecting the 'class' and 'params' stuff to be there.
It seems like you should create $this->meta as an array for the metadata about the objects you are storing, and keep $this->objects purely for the objects themselves.b
Posted: Sun Jul 23, 2006 4:53 pm
by Christopher
Jason is right. Perhaps it would be clearer if we created a little class just to hold these bits of information about a class/file/object. An object might also allows us to add other features more easily. Something as simple as:
Code: Select all
class Registry_Entry {
var $class;
var $name;
var $path;
var $params;
}
Posted: Tue Jul 25, 2006 2:08 am
by Luke
I went ahead and just used a seperate array for now... I am considering using a seperate class for the entries though... I just can't think of why I would need to. What other features are there? Here it is...
Code: Select all
<?php
class Registry{
private $objects;
private $entries;
private $path;
private $prefix;
private $suffix;
function __construct($path='/', $suffix='.inc.php', $prefix='') {
// Path to classes
$this->path = $path;
// Allows for classes to be searched out by a prefix such as ClassSession.inc.php (Where Class is the prefix)
$this->prefix = $prefix;
// Allows for classes to be suffixed and have any allowed extension
$this->suffix = $suffix;
}
private function instantiate($class, $name) {
if(!is_object($name)){
$arglist = array();
if (isset($this->entries[$name]['params'])) { // there are args
$n = count($this->entries[$name]['params']);
for ($i=0; $i<$n; ++$i) {
$arglist[$i] = "\$this->entries['$name']['params'][$i]";
}
}
//ob_start(); // This doesn't prevent jack, does it?
eval ("\$object = new " . "\$class(" . implode(', ', $arglist) . ');');
//ob_end_clean();
// Unset registry entry as it is no longer needed
unset($this->entries[$name]);
// Store object in registry
$this->objects[$name] = $object;
}
return $object;
}
public function register($class, $name=null /*, $arg1, $arg2... */){
// If object name is not set, object is named the same as it's class
if(is_null($name)) $name = $class;
// Store object's classname and params temporarily (if class hasn't already been registered)
if(!isset($this->entries[$name])){
$params = func_get_args();
array_shift($params); // Remove $name from param list
array_shift($params); // Remove $class from param list
// Register params
$this->entries[$name]['params'] = $params;
$this->entries[$name]['class'] = $class;
}
}
// TODO: Make child classes autoload their parent before instantiation
private function load($class){
if (! class_exists($class)) {
include($this->path . $this->prefix . $class . $this->suffix);
}
}
public function get($name){
// If object has already been stored
if(isset($this->objects[$name]) && is_object($this->objects[$name])){
// Set return value to stored object
$object = $this->objects[$name];
}
else{
// Load the class file
$this->load($this->entries[$name]['class']);
// Instantiate class
$object = $this->instantiate($this->entries[$name]['class'], $name);
}
// Return object id
return $object;
}
}
?>
Posted: Tue Aug 01, 2006 12:53 am
by Luke
This isn't meant to be a bump, just posting my newest version of this: I used an array for entries and I added the setParams method so you don't have to specify the parameters in the construct if you don't want to. I also set a $path parameter in the get method so you can specify what directory to get the class from (if not the one set in the construct)
Code: Select all
<?php
class Registry{
private $objects;
private $entries;
private $path;
private $prefix;
private $suffix;
function __construct($path='/', $suffix='.inc.php', $prefix='') {
// Path to classes
$this->path = $path;
// Allows for classes to be searched out by a prefix such as ClassSession.inc.php (Where Class is the prefix)
$this->prefix = $prefix;
// Allows for classes to be suffixed and have any allowed extension
$this->suffix = $suffix;
}
private function instantiate($class, $name) {
if(!is_object($name)){
$arglist = array();
if (isset($this->entries[$name]['params'])) { // there are args
$n = count($this->entries[$name]['params']);
for ($i=0; $i<$n; ++$i) {
$arglist[$i] = "\$this->entries['$name']['params'][$i]";
}
}
//ob_start(); // This doesn't prevent jack, does it?
eval ("\$object = new " . "\$class(" . implode(', ', $arglist) . ');');
//ob_end_clean();
// Unset registry entry as it is no longer needed
unset($this->entries[$name]);
// Store object in registry
$this->objects[$name] = $object;
}
return $object;
}
public function register($class, $name=null /*, $arg1, $arg2... */){
// If object name is not set, object is named the same as it's class
if(is_null($name)) $name = $class;
// Store object's classname and params temporarily (if class hasn't already been registered)
if(!isset($this->entries[$name])){
$params = func_get_args();
array_shift($params); // Remove $name from param list
array_shift($params); // Remove $class from param list
// Register params
$this->entries[$name]['params'] = $params;
$this->entries[$name]['class'] = $class;
}
}
// TODO: Make child classes autoload their parent before instantiation
private function load($class, $path, $suffix, $prefix){
$path = $path ? $path : $this->path;
$suffix = $suffix ? $suffix : $this->suffix;
$prefix = $prefix ? $prefix : $this->prefix;
if (! class_exists($class)) {
require_once($path . $prefix . $class . $suffix);
}
}
public function setParams($name, $params){
if(isset($this->entries[$name]) && !is_object($this->objects[$name])) $this->entries[$name]['params'] = $params;
}
public function get($name, $path=false, $suffix=false, $prefix=false){
// If object has already been stored
if(isset($this->objects[$name]) && is_object($this->objects[$name])){
// Set return value to stored object
$object = $this->objects[$name];
}
else{
if(!isset($this->entries[$name])){
$this->register($name);
}
// Load the class file
$this->load($this->entries[$name]['class'], $path, $suffix, $prefix);
// Instantiate class
$object = $this->instantiate($this->entries[$name]['class'], $name);
}
// Return object id
return $object;
}
}
?>
Posted: Sat Aug 12, 2006 5:49 pm
by Hurreman
Just started re-writing a lot of my code the other day, and this reminded me of the Service Locator I was struggling with a while back.
I remember bashing my head to the desk a lot when figuring out a way to pass eventual parameters to the requested classes, and never really got too happy with the result. I just go stuck with my setArgs-method.
I know my solution is crap, but sometimes you get ideas just from looking at someone elses code. So here is my current Service Locator:
Code: Select all
<?php
class Locator
{
private $objects = array();
private $args = array();
// Empty construct
public function __construct()
{
}
// Add module to array
public function set($handle,&$class)
{
$this->objects[$handle] =& $class;
}
// Set arguments
public function setArgs($handle)
{
$args = array();
if(func_num_args()>1)
{
for($i=1;$i<func_num_args();$i++)
{
$args[$i-1] = func_get_arg($i);
}
}
$this->args[$handle] = $args;
}
// Fetch arguments
public function getArgs($handle)
{
return $this->args[$handle];
}
// Fetch module from array
public function get($handle,$args)
{
// Check if the requested object exists
if(!isset($this->objects[$handle]))
{
if(!isset($this->objects[$handle]))
{
if(!class_exists($handle))
{
@include_once($handle . '.php');
}
if(class_exists($handle))
{
// If the module has any arguments, pass them as well
if(isset($this->args[$handle]))
{
if(count($this->args[$handle])==1)
{
$arg = $this->args[$handle][0];
$this->objects[$handle] =& new $handle($arg);
}
else
{
$this->objects[$handle] =& new $handle($this->args[$handle]);
}
}
else
{
$this->objects[$handle] =& new $handle();
}
}
}
}
return $this->objects[$handle];
}
}
?>
Keep up the great work! Can't wait to see the final result
