Service Locator

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
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

arborint wrote:That is a good question. We are going to need a way to do that. It can be manual by providing a list of dependent classes. It can also be automatic by using reflection or class function or __autoload(). So there are times when we might want the Registry to handle it and other times when we want to solve the problem outside. Another external solution could be as simple as including the inherited class file in the class file that uses it. We should solve the problems we can an not probibit external solutions.
I think that a require_once('parent.inc.php'); in the child class file would be sufficient for this... I would prefer for the registry class to be as small and uncomplicated as possible. Unless we can find a very simple way for the registry to load a parent, let's just do this for now.

I'm going to work on it a little more and see if I can't implement the lazy load you are talking about.

I would just prefer for the class to have as little public methods as possible... I am trying to make sure that this class has a very simple interface so that should I decide to change its internal workings, it will effect very little outside of itself.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

The Ninja Space Goat wrote:I think that a require_once('parent.inc.php'); in the child class file would be sufficient for this... I would prefer for the registry class to be as small and uncomplicated as possible. Unless we can find a very simple way for the registry to load a parent, let's just do this for now.
I am not sure exactly what you mean about the child class file? I would not worry too much about "small and uncomplicated" to much -- just add the features in a well designed way -- we can always refactor later.
The Ninja Space Goat wrote:I'm going to work on it a little more and see if I can't implement the lazy load you are talking about.
The Lazy Load adds some internal data to save things in. They question is: separate arrrays or a little object to hold the info?

The Ninja Space Goat wrote:I would just prefer for the class to have as little public methods as possible... I am trying to make sure that this class has a very simple interface so that should I decide to change its internal workings, it will effect very little outside of itself.
Again, I wouldn't worry about that too much. There are still a number of features in my list above to go.
(#10850)
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

arborint wrote:
The Ninja Space Goat wrote:I think that a require_once('parent.inc.php'); in the child class file would be sufficient for this... I would prefer for the registry class to be as small and uncomplicated as possible. Unless we can find a very simple way for the registry to load a parent, let's just do this for now.
I am not sure exactly what you mean about the child class file? I would not worry too much about "small and uncomplicated" to much -- just add the features in a well designed way -- we can always refactor later.
I mean this:

SessionChild.inc.php

Code: Select all

<?php
require_once('Session.inc.php'); // Loading my parent
class SessionChild extends Session{
	function _druct(){
		$this->start();
	}
}
?>
My only problem with this is that it would mean that all class files would have to be in the same directory or the flexibility provided by our registry's prefix parameter is lost.
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

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, $params, $name) {
	    
		//ob_start(); // This doesn't prevent jack, does it?
        eval ("$" . "object = new {$class}(" . implode(', ', $params) . ');');
		//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, $params=array(), $name=null){
			
		// 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])){
            $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']);
		
		// Instantiate class
		$object = $this->instantiate($this->objects[$name]['class'], $this->objects[$name]['params'], $name);
		
    	// Return object id
    	return $object;
    	
	}
}
?>
:D :D :D I think this is much better... arborint?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

The Ninja Space Goat wrote:My only problem with this is that it would mean that all class files would have to be in the same directory or the flexibility provided by our registry's prefix parameter is lost.
Ok ... there are a couple of things we can do here. One is to allow PEAR style class/file naming and convert underscores to slashes when creating the file name from the class name. So "My_Class" is in file "My/Class.php". I think we should add that, but we can make it so you can turn it off if you want.

Another thing we can do is the last item in my original list -- which is Todd_Z's suggestion to allow a list of paths that load() will search. It can be a parameter to load() or passed when to the constructor. It really depends on what the real use cases are. Maybe Todd_Z can give us some insight on whether we only need a global set of search paths or whether we need individual sets for each class?

This is also a question of internal/external handling again, because you can just as easily add those paths to PHP's search path and achieve the same thing. So I guess the question is: is this a popular/requested option?
The Ninja Space Goat wrote: :D :D :D I think this is much better... arborint?
Yes, yes, yes ... definitely getting there.
(#10850)
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

arborint wrote:Yes, yes, yes ... definitely getting there.
Don't be afraid to criticize... everybody please be as critical as possible.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Just wanted to butt in and say I love seeing people go from complete newbies, and then hit a point where they clearly begin to excel. I notice it a lot here. I think you've hit that point where you're rapidly gaining an advanced understanding ~Space Goat. Kudos :)
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

why... thank you. :D

I owe it all to this forum...
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

You're implode (within eval()) will need to use :

Code: Select all

implode ("', '", $params)
:)

it's still open to security holes btw - I'm still working on an alternative (when I get time :))
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

yes I am working on it too... nothing else seems to work. I can't get it to accept multiple params without eval. It wants to accept it all as one.. :evil:

I will attempt to sanitize the input for now.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Jenk wrote:You're implode (within eval()) will need to use :

Code: Select all

implode ("', '", $params)
:)

it's still open to security holes btw - I'm still working on an alternative (when I get time :))
Actually you should look at the trick I am doing here which is to pass the array elements, not the values.
(#10850)
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

Trying to do that trick, but I think I drank too much coffee today, and it just isn't working. I'll try a little more when I get home...
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

I think I got it...

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, $params, $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])){
	    	
            if (func_num_args() > 2) {            // args were passed
                    $params = func_get_args();
					// Unset name and class from params as they are not params
					array_shift($params);
					array_shift($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']);
		
		// Instantiate class
		$object = $this->instantiate($this->objects[$name]['class'], $this->objects[$name]['params'], $name);
		
    	// Return object id
    	return $object;
    	
	}
}
?>
Except I just turned on notices and I'm now getting these notices...
Notice: Use of undefined constant Session - assumed 'Session' in c:\wamp\www\module_admin\classes\Registry.inc.php(29) : eval()'d code on line 1

Notice: Use of undefined constant name - assumed 'name' in c:\wamp\www\module_admin\classes\Registry.inc.php(29) : eval()'d code on line 1

Notice: Use of undefined constant name - assumed 'name' in c:\wamp\www\module_admin\classes\Registry.inc.php(29) : eval()'d code on line 1
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

It should be:

Code: Select all

$arglist[$i] = "\$this->objects['$name']['params'][$i]";
(#10850)
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

Awesome!! So what's left on that list...
Post Reply