I'm trying to decide the design of a system which is meant to allow for a high amount of extensiblity. From what I can tell, a pattern such as the abstract factory would not allow for overriding of the base methods, apart from duplicating code (as demonstrated below).
I've done some preliminary research into aspect oriented programming and it seems to be along the lines of what I'm looking for but I'm having a difficult time wrapping my head around the specifics.
abstract class Object {
protected $object_id;
protected $name;
function LoadObjectData()
{
$file_contents = readfile('object'.$object_id.'.data');
$data = array();
// parse file contents into $data array...
return $data;
}
function Create()
{
$data = $this->LoadObjectData();
$name = $data['name'];
return $data;
}
}
class User extends Object {
protected $email_address;
function Create()
{
$data = parent::Create();
$this->email_address = $data['email_address'];
return $data;
}
}
//----------Module 1-MySQL Lookup-------------
/*
* Redefine Object::LoadObjectData() as follows:
*/
function LoadObjectData()
{
$data = array();
$result = mysql_query("SELECT...");
// construct array from result set
return $data;
}
//----------Module 2-Cache Machine-------------
/*
* Redefine Object::LoadObjectData() as follows:
*/
function LoadObjectData()
{
if (exists_in_cache($object_id)) {
return get_cached_object($object_id);
}
$data = parent::LoadObjectData();
cache_object($object_id, $data);
return $data;
}
(This is sort of a poor example, but hopefully it helps to get my point across)
The intended system would have a very large proportion of methods available to be extended and I would like to minimize the extra effort and learning necessary for developers.
Is AOP exactly what I'm looking for, or is there a better way to deal with this?
Thanks!
So, you want to use a decorator pattern without defining the decorator itself.
If yes, then it's a monkeypatching and can be done with aspect-oriented tools. This can be solved easily with following extensions and frameworks:
PHP Runkit Extension
Go! Aspect-Oriented framework for PHP
PHP-AOP Extension.
You don't have to declare the base class as an abstract class. You can make it a regular class and have it load and instantiate other classes based on passed construct parameters. The constructor can return an instance of a class, not just the class the constructor is in. To avoid duplicating code, you can mix static with instantiated functions and variables. Just remember that a static function or variable is the same for ALL instances. Change a static variable in one and it is changed for all instances. A rather basic example of a plugin architecture.
class BaseObject {
protected static $cache = array();
public function __construct($load_plugin) {
require_once($load_plugin.'.class.php');
$object = new $load_plugin();
return $object;
}
public static function cacheData($cache_key, $data) {
self::$cache[$cache_key] = $data;
}
}
class Plugin extends BaseObject {
public function __construct() {
}
public function loadData() {
// Check the cache first
if ( !isset(self::$cache[$cache_key]) ) {
// Load the data into cache
$data = 'data to cache';
self::cacheData($cache_key, $data);
}
return self::$cache[$cache_key];
}
}
Related
I have the following code (simplified and details changed for this question):
class model_to_be_tested {
// an array that holds a collection of thing A
public $array_of_thing_A;
// already doing constructor injection for the data object
public __construct($data_object) {
// details here
}
public function add_new_thing_A($has_relationship) {
$thing_A = new Thing_A();
$thing_A->is_thing = true;
$thing_A->has_relationship_with_thing_B = $has_relationship;
if ($has_relationship) {
$thing_B = new Thing_B();
$thing_A->relationship_with = $thing_B;
}
$this->array_of_thing_A[] = $thing_A;
}
}
In the above example, I have to decouple the instantiation of Thing_A and Thing_B from the add_new_thing method. However, a simple constructor injection will not do for these two classes. This is because I need fresh instances of Thing_A and Thing_B every time add_new_thing is called so that Thing_A can be added to the array_of_thing_A.
How can I make this function unit testable? And more specifically for me to use mocks of Thing_A and Thing_B in testing this function in PHPUnit?
Any suggestions with code example will be appreciated.
Additionally, I would like to mention that Thing_A and Thing_B are used elsewhere in the codebase that I am working with and the code using these classes will eventually need to be unit tested. Solutions that are too localized and would cause repeated code elsewhere will not be too ideal in my situation. Thank you.
As commenter xmike mentioned, you could use the factory pattern. You would inject a factory object through the ctor as well. Then you could have a factory that provides simplified instances of your Thing_A and Thing_B.
class ThingFactory {
public function buildThingA() {
return new Thing_A(); // or MockThing_A if you go the ducktyping route
}
public function buildThingB() {
return new Thing_B();
}
}
class model_to_be_tested {
// an array that holds a collection of thing A
public $array_of_thing_A;
// you could go the typed route and have an interface for this
private $factory;
// already doing constructor injection for the data object
public __construct($data_object, $factory) {
// details here
$this->factory = $factory;
}
public function add_new_thing_A($has_relationship) {
$thing_A = $this->factory->buildThingA();
$thing_A->is_thing = true;
$thing_A->has_relationship_with_thing_B = $has_relationship;
if ($has_relationship) {
$thing_B = $this->factory->buildThingB();
$thing_A->relationship_with = $thing_B;
}
$this->array_of_thing_A[] = $thing_A;
}
}
PHP is such a strange language, you can't assign a class to a variable. But you can do it as a string. Inject ThingA and ThingB on the constructor as strings. You can call new on the string member.
class ThingA {};
class ThingB{};
class model_to_be_tested {
// an array that holds a collection of thing A
public $array_of_thing_A;
private $_thingA;
private $_thingB;
public function __construct($data_object, $thingA, $thingB) {
$this->_thingA = $thingA;
$this->_thingB = $thingB;
}
public function add_new_thing_A($has_relationship) {
$thing_A = new $this->_thingA();
if ($has_relationship) {
$thing_B = new $this->_thingB();
}
$this->array_of_thing_A[] = $thing_A;
}
}
$model = new model_to_be_tested('foo', 'ThingA', 'ThingB');
$model->add_new_thing_A(true);
There's a live version here: https://repl.it/#rmoskal/InconsequentialAnotherGermanshorthairedpointer
Or provide a static constructor for the class.
Let's say that I'm building a class (for a generic purpose) and I have two methods that work on common variables.
class renderElement
{
public function process()
{
$output = array();
$data = $this->supportMethod($output);
// do stuff with $output
}
public function supportMethod(&$processed_output)
{
// do stuff with $processed_output
}
}
I want to use the same variable into both methods; let's say $output.
I'm curious to know the theory behind the choice of eventually rely on a class property (like following) or when instead is ok (or better) to pass the variable as reference.
class renderElement
{
private $output = array();
public function process()
{
$data = $this->supportMethod();
// do stuff with $this->output
}
public function supportMethod()
{
// do stuff with $this->output
}
}
Advantages? Disadvantages? Design suggestions?
Suggested lectures about this kind of design choices?
[ EDIT ]
I would add that the variable/property should obviously have sense as an object property. I'm not talking about variables for just supporting data processing.
An object fundamentally consists of two things, behaviour and state.
Methods of your class define the behaviour of your object.
Attributes of your class define the state of your object.
In your first example, $output isn't a part of the object's state, so it will not persist throughout the life of the object.
In your second example, $output will persist throughout the life of the object since it is a part of the object's state.
Take this example...
class Shape
{
protected $sides;
public function getNumberOfSides()
{
return $this->sides;
}
}
class Triangle extends Shape
{
public function __construct()
{
$this->sides = 3;
}
}
class Square extends Shape
{
public function __construct()
{
$this->sides = 4;
}
}
$shape = new Square;
echo $shape->getNumberOfSides(); // Returns 4
$shape = new Triangle;
echo $shape->getNumberOfSides(); // Returns 3
$sides (number of sides) is an intrinsic part of a shapes nature, therefore it is appropriate for it to be a part of the object's state throughout the life of the object. This doesn't really have anything to do with the convenience of passing parameters between methods in the same class.
I am creating my own MVC framework, just to learn something new and ran into this problem recently.
Lets say I have like this:
Class Post extends \application\BaseClass
{
private $objPostDetail = null;
private $objAuthor = null
private $objCategory = null;
private $objType = null;
private $objTitlePicture = null;
public function __construct(PostDetail $objPostDetail,
Author $objAuthor,
Category $objCategory,
Type $objType,
TitlePicture $objTitlePicture)
{
$this->objPostDetail = $objPostDetail;
$this->objAuthor = $objAuthor;
$this->objCategory = $objCategory;
$this->objType = $objType;
$this->objTitlePicture = $objTitlePicture;
}
}
Then some objects used in the constuctor can also be comlex to create.
I get data for it from PostDAO class, which returns array of data.
Now the problem is how to create new instance of this class, since it may be on many places in the application.
I think create everywhere $objAuthor, then $objCategory etc. to finally create $objPost is not good. So I created what I think may be called a Factory:
Class PostFactory extends \application\BaseFactory
{
private $arrData = null;
private $objPostDetail = null;
private $objCategory = null;
private $objType = null;
private $objTitlePicture = null;
public function __construct($arrData)
{
$this->arrData = $arrData;
}
public function build()
{
$this->objPostDetail = $this->buildPostDetail();
$this->objCategory = $this->buildCategory();
$this->objType = $this->buildType();
$this->objTitlePicture = $this->buildTitlePicture();
return $this->buildPost();
}
private function buildPostDetail()
{
$objPostDetail = new \includes\classes\factories\PostDetailFactory($this->arrData);
return $objPostDetail->build();
}
private function buildCategory()
{
$objCategory = new \includes\classes\factories\CategoryFactory($this->arrData);
return $objCategory->build();
}
private function buildType()
{
$objType = new \includes\classes\factories\TypeFactory($this->arrData);
return $objType->build();
}
private function buildTitlePicture()
{
$objTitlePicture = new \includes\classes\factories\TitlePictureFactory($this->arrData);
return $objTitlePicture->build();
}
private function buildPost()
{
return new \includes\classes\Post($this->objPostDetail, $this->objCategory,
$this->objType, $this->objTitlePicture);
}
}
It works well, but I don't like that I have twice as much classes and I don't know what parameters do I need for instantiating Post since I pass array to the Factory class (because I want to avoid many parameters in the constructor).
So, my question is what is the best way how to create an instance of class like this?
Thanks in advance for any help.
If you want to create your own MVC framework, I strongly suggest starting with some sort of "Container" which holds instances of service classes (classes that only have to be initialized once, for example Request or Response).
Use reflection classes to automatically inject the parameters a constructor needs by iterating over the function arguments of the constructor.
See the following example of an idea I usually use. It's very reliable and reasonably fast. If your framework has a LOT of different classes and you depend on this functionality a lot, I strongly recommend implementing some way of caching the parameter lists from the reflection classes.
<?php
class SomeClass
{
public function __construct(Request $request, Response $response, $title = '')
{
echo get_class($request);
// will output "Request"
echo $title;
// will output "Hello World"
}
}
// This function will handle the dynamic dependency injection to make sure the constructor gets the arguments passed that it needs, with optional named arguments passing.
$some_class = YourFrameworkDispatcherClass->createInstance('SomeClass', array('title' => 'Hello World'));
?>
I've actually written a blog post about this on my blog. http://harold.info/engineering/php-dynamic-dependency-injection/
I think this can help you out with this structural problem.
I have a Display object that handles HTML output of the script. It has a mode property, which defines many aspects of how the output is generated. There are several modes, and I will probably add more later. Each mode implies it's own parameters. For example, an author mode would imply an authorID. A search mode would imply a Search object as a parameter, which would contain query information. A comment mode would imply a postID and commentID parameters.
So, a mode has a name and some number of parameters, depending on the name.
I decided to create a Display_Mode object, which has two properties: name and parameters. But how do I assign parameters to names? So that if I have a comment mode, it would neccessarily mean that there are postID and commentID parameters?
My current solution is this:
class display_mode{
public $name;
public $params;
public function __construct($name)
{
$this->name = $name;
switch ($this->name){
case 'comment':
$this->params = array('postID', `commentID`);
break;
case 'author':
$this->params = array('authorID');
}
//etc..
}
}
This seems a bit messy. Is there a better way?
UPD: given answers led me to ask another question, concerning the whole design, which also provides context for this one.
You're better off abstracting the common functionality of the Display_Mode class into an abstract base class or interface and then defining each individual mode as a class that inherits from the base class (or implements the interface).
These specialised mode classes would then explicitly define the parameters they require in their constructors and/or methods, and would be responsible for producing the output that each "mode" requires.
It's difficult to give more specific advice than this without knowing exactly what your Display_Mode class is supposed to do, however.
The idea here is that you should avoid do-it-all classes in OOP, preferring small, self-contained classes each with a single purpose. By giving each mode its own class that can independently render its content, you're making it easy to change the way display modes work or add new ones. All you have to do is add a new class.
This is known as loose coupling.
The description is kinda confusing, but I would create an adapter for each possible "parameter" of Display. This adapter could provide single interface, independently of the the resource that you want to display.
$parameter = new UnknownPrameter;
$adapterFactory = new AdapterFactory;
$parameter = $adapterFactory->build( $parameter );
$display->present( $parameter );
Where AdapterFactory::build() create a wrapper for the specific type of parameter, that you supplied. The returned instance is a container for that parameter.
This approach would also prevent the computation from accumulating in the constructor, which would make the code harder to test/expand.
#Will Vousden already gave you the answer. This is a quick example of how to approach your problem.
abstract class DisplayMode {
protected $_params = array();
public function __construct(array $params) {
$this->_params = $params;
}
public function hasParameter($key) {
if (array_key_exists($key, $this->_params)) {
return true;
}
return false;
}
public function setParameters(array $params) {
$this->_params = $params;
return $this;
}
public function getParameters() {
return $this->_params;
}
}
class CommentMode extends DisplayMode {
public function getCommentId() {
if ($this->hasParameter('comment_id')) {
return $this->_params['comment_id'];
}
return null;
}
public function getPostId() {
if ($this->hasParameter('post_id')) {
return $this->_params['post_id'];
}
return null;
}
}
class AuthorMode extends DisplayMode {
public function getAuthorId() {
if ($this->hasParameter('author_id')) {
return $this->_params['author_id'];
}
return null;
}
}
$comment = new CommentMode(array('post_id' => 4, 'comment_id' => 2));
$author = new AuthorMode(array('author_id' => 3));
// example
print $comment->getCommentId() . ' - ' . $comment->getPostId() . ' - ' . $author->getAuthorId();
I'm working on creating a domain layer in Zend Framework that is separate from the data access layer. The Data Access Layer is composed to two main objects, a Table Data Gateway and a Row Data Gateway. As per Bill Karwin's reply to this earlier question I now have the following code for my domain Person object:
class Model_Row_Person
{
protected $_gateway;
public function __construct(Zend_Db_Table_Row $gateway)
{
$this->_gateway = $gateway;
}
public function login($userName, $password)
{
}
public function setPassword($password)
{
}
}
However, this only works with an individual row. I also need to create a domain object that can represent the entire table and (presumably) can be used to iterate through all of the Person's in the table and return the appropriate type of person (admin, buyer, etc) object for use. Basically, I envision something like the following:
class Model_Table_Person implements SeekableIterator, Countable, ArrayAccess
{
protected $_gateway;
public function __construct(Model_DbTable_Person $gateway)
{
$this->_gateway = $gateway;
}
public function current()
{
$current = $this->_gateway->fetchRow($this->_pointer);
return $this->_getUser($current);
}
private function _getUser(Zend_Db_Table_Row $current)
{
switch($current->userType)
{
case 'admin':
return new Model_Row_Administrator($current);
break;
case 'associate':
return new Model_Row_Associate($current);
break;
}
}
}
Is this is good/bad way to handle this particular problem? What improvements or adjustments should I make to the overall design?
Thanks in advance for your comments and criticisms.
I had in mind that you would use the Domain Model class to completely hide the fact that you're using a database table for persistence. So passing a Table object or a Row object should be completely under the covers:
<?php
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();
$db = Zend_Db::factory('mysqli', array('dbname'=>'test',
'username'=>'root', 'password'=>'xxxx'));
Zend_Db_Table_Abstract::setDefaultAdapter($db);
class Table_Person extends Zend_Db_Table_Abstract
{
protected $_name = 'person';
}
class Model_Person
{
/** #var Zend_Db_Table */
protected static $table = null;
/** #var Zend_Db_Table_Row */
protected $person;
public static function init() {
if (self::$table == null) {
self::$table = new Table_Person();
}
}
protected static function factory(Zend_Db_Table_Row $personRow) {
$personClass = 'Model_Person_' . ucfirst($personRow->person_type);
return new $personClass($personRow);
}
public static function get($id) {
self::init();
$personRow = self::$table->find($id)->current();
return self::factory($personRow);
}
public static function getCollection() {
self::init();
$personRowset = self::$table->fetchAll();
$personArray = array();
foreach ($personRowset as $person) {
$personArray[] = self::factory($person);
}
return $personArray;
}
// protected constructor can only be called from this class, e.g. factory()
protected function __construct(Zend_Db_Table_Row $personRow) {
$this->person = $personRow;
}
public function login($password) {
if ($this->person->password_hash ==
hash('sha256', $this->person->password_salt . $password)) {
return true;
} else {
return false;
}
}
public function setPassword($newPassword) {
$this->person->password_hash = hash('sha256',
$this->person->password_salt . $newPassword);
$this->person->save();
}
}
class Model_Person_Admin extends Model_Person { }
class Model_Person_Associate extends Model_Person { }
$person = Model_Person::get(1);
print "Got object of type ".get_class($person)."\n";
$person->setPassword('potrzebie');
$people = Model_Person::getCollection();
print "Got ".count($people)." people objects:\n";
foreach ($people as $i => $person) {
print "\t$i: ".get_class($person)."\n";
}
"I thought static methods were bad
which is why I was trying to create
the table level methods as instance
methods."
I don't buy into any blanket statement that static is always bad, or singletons are always bad, or goto is always bad, or what have you. People who make such unequivocal statements are looking to oversimplify the issues. Use the language tools appropriately and they'll be good to you.
That said, there's often a tradeoff when you choose one language construct, it makes it easier to do some things while it's harder to do other things. People often point to static making it difficult to write unit test code, and also PHP has some annoying deficiencies related to static and subclassing. But there are also advantages, as we see in this code. You have to judge for yourself whether the advantages outweigh the disadvantages, on a case by case basis.
"Would Zend Framework support a Finder
class?"
I don't think that's necessary.
"Is there a particular reason that you
renamed the find method to be get in
the model class?"
I named the method get() just to be distinct from find(). The "getter" paradigm is associated with OO interfaces, while "finders" are traditionally associated with database stuff. We're trying to design the Domain Model to pretend there's no database involved.
"And would you use continue to use the
same logic to implement specific getBy
and getCollectionBy methods?"
I'd resist creating a generic getBy() method, because it's tempting to make it accept a generic SQL expression, and then pass it on to the data access objects verbatim. This couples the usage of our Domain Model to the underlying database representation.