I'm developing a PHP framework; it started off as application-specific, however it has moved into a more agnostic HMVC-style platform which I intend on re-purposing for further projects.
Anyways, while I'm the only developer on the project as it stands, I'm a bit conflicted on my choices of developing the core interfaces.
My main question is (and I understand this could be deemed slightly subjective) is it more appropriate to create a strict interface through which client programmers will work, or permit a bit more flexibility. This is best described through an example:
class MyDataClass{
public function getData($key){}
public function setData($key, $value){}
}
This satisfies the requirements (save for implementation details) of a simple data registry. The methods are chain-able by returning $this
, and can contain necessary validation logic. Now the alternative PHP approach:
class MyDataClass{
public function __get($key){}
public function __set($key, $value){}
}
Sure that works too, and provides a clean implementation through the use of PHP's magic. Now, the approach I've seemed to take most often is:
class MyDataClass{
public function getData($key){}
public function setData($key, $value){}
public function __get($key){ return $this->getData($key); }
public function __set($key){ $this->setData($key); }
}
Is providing multiple entry points as this example shows a poor choice in design? I always figured it would be a good idea, by centralizing any interaction logic to a single method, but permitting different syntactic choices. I'm now reconsidering this, in favor of a much stricter entry point. A less brief example:
class MySuperDataClass implements ArrayAccess{
// these do the work
public function getData($key){}
public function setData($key, $value){}
public function getChild($name){}
public function setChild($name, self $child){}
// these are just sugary synonyms
public function offsetGet($key){}
public function offsetSet($key, $value){}
public function __get($name){}
public function __set($name, self $child){}
// ...
}
Thoughts?
I realized after OZ_'s response that I hadn't justified my choice, for understanding the intent of my approach.
For instance, direct method calls (getData()
for example) would be used in controllers, to bind data to a view.
$view->setData('foo', 'bar')
->setData('alpha', 'beta')
->setData('hello', 'world');
Whereas magic sugar is used in view generation for readability and brevity.
<p><?php echo $view['foo']; ?></p>
<p><?php echo $view['alpha']; ?></p>
<p><?php echo $view['hello']; ?></p>
This is how I came to such a convention. I still think it's a nice approach, but as this question alludes, I'm on the fence now in favor of better practices.
Also: Performance is becoming a concern, as I see the application growing, and these calls are being made iteratively, by using the sugar I'm doubling up my call stack. Sure, micro-optimization I know, but I would think bottleneck potential increases, especially when dealing with PHP magic (if I've been led to understand correctly, especially __call()
) The only way to check is to profile, sure; I've always been a premature optimizer, a habit I'd like to break. Breaking poor design habits is important too.
@jgauffin; the View classes implement ArrayAccess
, Iterator
and Countable
for this behavior, as well as making use of __get
/__set
magic. This is the sugar for the view, whereas the raw methods are called to bind data from the controllers.
<?php if($view->canRender('post')): ?>
<div>
<?php foreach($view->post as $post): ?>
<p><?php echo $post['text']; ?></p>
<?php if($post->canRender('comments')): ?>
<div>
<?php foreach($post->comments as $comment): ?>
<p><?php echo $comment['text']; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
Thoughts: