Page 3 of 4

Posted: Thu Jul 20, 2006 1:26 pm
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.

Posted: Thu Jul 20, 2006 3:37 pm
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.

Posted: Thu Jul 20, 2006 7:40 pm
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.

Posted: Thu Jul 20, 2006 8:34 pm
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?

Posted: Fri Jul 21, 2006 1:04 am
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.

Posted: Fri Jul 21, 2006 3:02 am
by Luke
arborint wrote:Yes, yes, yes ... definitely getting there.
Don't be afraid to criticize... everybody please be as critical as possible.

Posted: Fri Jul 21, 2006 5:15 am
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 :)

Posted: Fri Jul 21, 2006 9:12 am
by Luke
why... thank you. :D

I owe it all to this forum...

Posted: Fri Jul 21, 2006 9:41 am
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 :))

Posted: Fri Jul 21, 2006 10:01 am
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.

Posted: Fri Jul 21, 2006 10:02 am
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.

Posted: Fri Jul 21, 2006 5:46 pm
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...

Posted: Fri Jul 21, 2006 8:00 pm
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

Posted: Fri Jul 21, 2006 8:29 pm
by Christopher
It should be:

Code: Select all

$arglist[$i] = "\$this->objects['$name']['params'][$i]";

Posted: Fri Jul 21, 2006 8:31 pm
by Luke
Awesome!! So what's left on that list...