Monday, August 10, 2009

PHP and singleton's

So I wanted to have use singletons in php, but couldn't find any good tuts that didn't involve cake or zend. I did quite a bit research and asking around and here is what I came up with. I framed the findings around Coldspring which is a ColdFusion dependency injection tool, which basically means it handles your objects for you.

First I have an xml file where I define where my objects (classes) are. If you are not familiar with MVC, I would first suggest reading up on it. But anyways, below I define some objects paths so I don't have to worry about where they are. As you can see I have an objects controller, service, and gateway.

<?xml version="1.0" encoding="ISO-8859-1"?>
<objects>

<object name="objectsController" type="controller" address="app/controllers/objectsController.php"/>
<object name="objectsService" type="service" address="app/services/objectsService.php"/>
<object name="objectsGateway" type="model" address="app/models/objects/objectsGateway.php"/>

</objects>

The next step is to read in the xml nodes. So below is a function that I feed a path to my xml file (above) and it returns me the nodes in PHP.

public function loadSimpleXML($xmlPath){
if (file_exists($xmlPath)) {
$xml = simplexml_load_file($xmlPath);
return $xml;
}else{
exit('Failed to open '.$xmlPath);
}
}

The next step I loop the nodes with the name "object" and do stuff with it.

//create singletons array to hold objects in
$singletons = array();

//get the count of the nodes
$cnt = count($xml->object);

//loop object nodes
for($i = 0; $i < $cnt; $i++) { $object = $xml->object[$i];

//get object name and address
$name = $this->getAttribute($object,"name");
$address = $this->getAttribute($object,"address");

//include the file
$this->loadClass($address);

//create an instances of the object
$pointer = (string)$name[0];
$singletons[$pointer] = new $pointer;

}

Alot of stuff happened in the above function so I will break it down by a few lines. First we get the node by doing:

$object = $xml->object[$i];

After we get the node I call a function to get the attributes of the node. In my case I just want the name and where the object file is at.

$name = $this->getAttribute($object,"name");
$address = $this->getAttribute($object,"address");

public function getAttribute($node,$name){
$attrs = $node->attributes();

return $attrs[$name];
}

Next I have to include the file. In PHP I found out you need to include the file if you want to use it. To do this I created a function that does a require_once(). I know you don't need a function for it but I figure it didn't hurt and this way if I have to do anything before my include or after I have the ability to do it now. In case you don't $this is used to call a function within a object file. Also you notice I have a variable call $GLOBALS["siteroot"]. I actually load up an environment xml file that takes of these properties but to be straight...the variable just contains the site root of my project, so no biggie here.

$this->loadClass($address);

public function loadClass($classPath){
require_once($GLOBALS["siteroot"].$classPath);
}

The next part was the hard part...dynamically creating an instance of the object. I found out that I needed to use a pointer to use "new", which took forever to figure out, because me and pointers don't mix (I just wanna chain stuff together). Anyways here's what I got.

//create an instances of the object
$pointer = (string)$name[0];

//append object to an array objects so they can be used later.
$singletons[$pointer] = new $pointer;

Later I store the $singleton's array in the $GLOBAL scope because it's the only scope that I know is some what persistant...but it's not. I don't think PHP has a persistant scope without creating a session. If any one has any ideas on where I can put this $singletons array so I don't to have read it from the xml everytime (if you caught the globals...I am techinically not fully using the singleton's pattern because I have no scope to put it in) I would greatly appreciate it, but I have found this works pretty slick for now.

No comments:

Post a Comment