Dependency Attachment

Last couple of threads I’ve been in here have been grousing about this problem. I recently got slightly burned with a dependency issue that took 20 minutes to figure out. After fixing it I moved to address the problem itself.

The class HTMLResponder needs a map of the available template files. This is normally provided by an array built by the SettingBuilder class during testing, or from a cache file during production. I was attaching the the output to core. After the little needle in haystack game I’m going to try this.


class HTMLResponder extends Responder {
	
	protected static $templateFiles = array();
	
	/**
	 * The name of the master template used to frame the page contents
	 * and write the HTML heading.
	 * 
	 * @var string
	 */
	protected static $masterTemplate = 'master';
	
	
	public static function setTemplates ( $templates ) {
		assert(is_array($templates));
		self::$templateFiles = $templates;
	}
	
	public static function setMasterTemplate( $master ) {
		self::$masterTemplate = strval($master);
	}
	
	public function __get( $var ) {
		// PHP is weird sometimes. This is a workaround so that instantiated
		// Responders can see the static properties of the class.	
		if ( $var == 'templateFiles') {
			return self::$templateFiles;
		} else if ($var == 'masterTemplate') {
			return self::$masterTemplate;
		} else {
			throw new FatalException('No access to '.$var);
		}
	}

That isn’t the whole class of course, just what’s relevant here. With this approach the HTMLResponder::setTemplates method needs to be called statically and the array supplied before any instances can be started.

I wonder why the makers of PHP saw fit to make the __get function above necessary (without it the instantiated objects cannot smoothly call the static elements in $this->var format ).

A Unit Tester can supply a proper array and run the class now without the rest of the framework being called. That should be useful eventually.

I don’t see why it is necessary or even what purpose it is serving. You can’t call static members with the “->” object operator. But you can with the scope resolution operator “::”. Why do you need to use the object operator? instantiated objects are fully capable of using the scope resolution operator to access static members, as your __get method itself demonstrates.

Why do you need to use $this->var instead of just doing self::$var within the code?

From the public scope, $instance::$var works as well, but that requires the static vars to be in the public scope.

Are you saying you want to access protected static vars from a public scope without them having to be public?

There was a __getStatic and __setStatic patch for this very purpose being kicked around PHP internals a bit back, but it didn’t get polished up enough for inclusion in PHP 5.3. Maybe one of these days somebody will get around to cleaning it up enough to be included in PHP 6.

One other thing bugging me, why the assert(is_array($templates)); in the setTemplates() method? Why not just make requiring it to be an array part of the contract:

public static function setTemplates ( array $templates )

Well, 2 things. Firstly, what about 2 templates with the same name? It’s just very constricting. Secondly, I (perhaps wrongly?) assumed you were suggesting “Dependency Attachment” as a design pattern beyond this single example. If so, this is a severe limitation.

Wrong. …


$responder = new HTMLResponder();
var_dump($responder->templateFiles);

Whether this works as expected or not depends on whether HTMLResponder::setTemplates() has been called before or after this code.

What if setTemplates() gets called twice? It will globally overwrite all your templates which may (probably will) cause undesired knock on effects throughout the application.

consider this:


HTMLResponder::setTemplates($templates);
$responder = new HTMLResponder();
var_dump($responder->templates);

//Elsewhere in the application, possibly another file
HTMLResponder::setTemplates($templates2);

//Back in the original location
var_dump($responder->templates);

The state of the object has changed, yet nothing has interacted with it. This breaks encapsulation.

What is that?

I’m assuming you mean why? You’d have to configure the DIC to call the specific static methods. This isn’t a problem in itself (other than needing extra DIC logic), but it needs to keep track of whether it should call setTemplates.


$responder1 = $factory->getResponder();
$responder1->doStuffInvolvingTemplates();

$responder2 = $factory->getResponder();

$responder1->outputTemplate();

If the factory calls HTMLResponder::setTemplates() prior to initialising the object, any changes made by $responder1 are lost.

When I tried static dependency injection, I had the constructor copy the current values of the statics into its own properties to get around exactly this problem.

Essentially you just have global variables. You may as well do:


 public function __get( $var ) {
        // PHP is weird sometimes. This is a workaround so that instantiated
        // Responders can see the static properties of the class.    
        if ( $var == 'templateFiles') {
            return $GLOBALS['templateFiles'];
        } else if ($var == 'masterTemplate') {
            return $GLOBALS['masterTemplate'];
        } else {
            throw new FatalException('No access to '.$var);
        }
    } 

Brainfart. Fixed in OP.

The day the user figures that out is the day UNIX stops working. Template names derive from the file names in the system.

I’m beginning to think I’m overkilling by building the array in the first place and should use the file system. The object itself should know where project and framework root are at. These are determined by external constants

That’s wonderful. Now if only there was a mechanic to hint at the type the return should have.

Have always been able to hint arrays.

5.3.99-dev has scalar hinting,

string
int
float
numeric
scalar
bool

float type hinting is effectively useless and you should probably use numeric, as whilst


function f(float $f) { }

f(2.); // works
f(2);  // fails

function n(numeric $n) { }

n(2.); // works
n(2);  // works

The Responder class is abstract. It manages the HTTP 1.0 protocol which means it is in charge of sending output headers, determining whether or not to compress the output, applying the compression and in production it uses a method that strips unnecessary white space. It demands it’s children define a response method that will guide the particulars of how they respond, and the controller expects to be able to call that method to send final output.

Oh, and your guess is right - it also contains that final echo call (though I’m using the print function instead of echo).

Never should happen. I’m very cautious about saying that because one of my credo’s is “There’s no never and no always” - that said, I cannot fathom an occasion where I would need more than one template library. Just as I can’t fathom the need for more than one class autoloader.

-You can’t guarantee the object is fully initialised after __construct()

Wrong. Templates by name is a shortcut. The template methods can be given an absolute path to a template and still work. A unit tester can test functionality that way, though to have fully tested the object it still should build a proper template map to test the ability to find templates off the map.

So if the the object is initialized without a map it will work just fine as long as you feed it the correct path to each template which, while tedious, is workable.

-you wont be able to easily use a DIC.

What is that?

Tom, at some point the application has to touch the damn ground. It can’t be insulated from everything, and any attempt to do so will cause huge amounts of bloat.

Dependencies are dangerous because of how they spawn interactions and unchecked it spirals out of control:

n * ( (n+1) / 2 )

But n can’t be 0, that would be no code at all. n also can’t be 1, because represents no interactions at all. The trick is to keep n low and manageable.

As for having an separate object read the templates in and pass them to the responder - that would work except that the responder would then have to use the eval() statement. Hmm… Let me think on that a moment. Use eval?

Hell no.

There is a RFC and patch for it http://wiki.php.net/rfc/returntypehint but hasn’t been applied.

I thought type hinting was limited to objects. I’d love to hint to array, string, boolean, integer, and so on.

Off Topic:

well that’s another issue of flexibility. 1) You’re tying your application to the filesystem. Imho, the content of a template and where that content came from are different responsibilities and should not be tied together. 2) What if there’s 2 or more different template directories? That’s surely desirable for organisation in any large project?

Not that any of this is at all relevant to your original post.

I used something similar (posted about it here: http://www.sitepoint.com/forums/showthread.php?t=629130 ) for a while.

While it works, it introduces clutter into your classes and blurs the API.

I have since gone off the idea. It basically forces a specific structure on classes which shouldn’t need to be there.

Your approach is simpler and less intrusive, but:

-Different instances of “HTMLResponder” can’t use different templates for different instances
-You can’t guarantee the object is fully initialised after __construct()
-you wont be able to easily use a DIC.

Hey Michael, I’m not sure I see the question, or whether you are even asking a question, so may I ask for more detail?

What is the purpose of the Responder base class? Is it what sends your template to the browser via ‘echo’???

Cheers,
Alex

What’s all this $class:: ?
Any particular reason you can’t use self:: ?