NotionCommotion Posted January 10, 2017 Share Posted January 10, 2017 I have the following classes as shown below... <?php //All classes except maybe Animals are NOT abstract class Animals { public $fee, $fi, $fo, $fum; public function __construct($settings) { foreach($settings as $key=>$value) { $this->$key=$value; } } } class Mammals extends Animals { public $mammalSpecific; } class Reptiles extends Animals { public $reptileSpecific; } class Dogs extends Mammals {} class Cats extends Mammals {} class Snakes extends Reptiles {} class Lizards extends Reptiles {} $dog=new Dogs(['fee'=>'x', 'fi'=>'x', 'fo'=>'x', 'fum'=>'x', 'mammalSpecific'=>'x']); $snake=new Snakes(['fee'=>'x', 'fi'=>'x', 'fo'=>'x', 'fum'=>'x', 'reptileSpecific'=>'x']); All is good, but now I want to get an object based on its ID. One option is to add a new class as follows: <?php class Factories //extends Nothing { private $settings; public function __construct($settings) { $this->settings=$settings; } public function getMammalByID($id) { if($classnameAndSpecificAboutThisMammal=$this->getClassnameAndSpecificAboutThisMammalForGivenID($id)) { $class=$classnameAndSpecificAboutThisMammal['classname']; $obj=new $class(array_merge($settings,['mammalSpecific'=>$classnameAndSpecificAboutThisMammal['specificAboutThisMammal']])); } return empty($obj)?new invalidObject:$obj; } public function getReptileByID($id) { if($classnameAndSpecificAboutThisReptile=$this->getClassnameAndSpecificAboutThisReptileForGivenID($id)) { $class=$classnameAndSpecificAboutThisReptile['classname']; $obj=new $class(array_merge($settings,['reptileSpecific'=>$classnameAndSpecificAboutThisReptile['specificAboutThisReptile']])); } return empty($obj)?new invalidObject:$obj; } } $factory=new Factory(['fee'=>'x', 'fi'=>'x', 'fo'=>'x', 'fum'=>'x']); $mammal=$factory->getMammalByID(123); $reptile=$factory->getReptileByID(321); Or should I just put a getByID() method in both the Mammals and Reptiles classes instead of using a separate Factory class? But wouldn't this force the Animal constructor (which will likely do more than I have shown) to be executed twice? Thanks Quote Link to comment Share on other sites More sharing options...
requinix Posted January 10, 2017 Share Posted January 10, 2017 Is this another one of your abstract questions that would be better answered if it wasn't abstract? What is the relationship between the IDs and the animals? The normal answer to "how do I get a thing based on ID" is "do a query for the information from the database and construct the object appropriately", but that doesn't seem right here. Quote Link to comment Share on other sites More sharing options...
kicken Posted January 10, 2017 Share Posted January 10, 2017 A factory is responsible for creating an instance of a given interface / abstract class based on some sort of criteria. For example when you asked about using React\EventLoop\Factory::create, the reason for using it is so that it can return the best event loop implementation available. It inspects the environment for various extensions before returning a generic option. In your animal case the factory would take some sort of data to identify what type of animal needs to be constructed and then do so accordingly. That might be an ID which is then looked up in the database or it might be an array with a specific member key. It might also be two separate arguments, one for the type and another for the context. The main purpose is to offload the construction to a central place, similar to how dependency injection makes the container responsible for construction of objects. Your factory might start out as simple as something like: public function getById($id){ $data = $this->lookupIdInDb($id); $class = $data['class']; return new $class($data); } but in the future end up more complex as your requirements change. Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted January 10, 2017 Author Share Posted January 10, 2017 What is the relationship between the IDs and the animals? The normal answer to "how do I get a thing based on ID" is "do a query for the information from the database and construct the object appropriately", but that doesn't seem right here. What makes you think it is abstract? Please know I only do so as I feel it makes it easier for others to provide answers, and definitely do so to make things easier for myself. I am using this pattern several places where the latest is a communication interface. One implementation is bi-directional using sockets and the other is a simple cron which utilizes curl. What is the relationship between the IDs and the animals? The normal answer to "how do I get a thing based on ID" is "do a query for the information from the database and construct the object appropriately", but that doesn't seem right here. Good question which I should have better described. I am using a super table with sub-tables for the more specific instances, so ID is the primary key and unique across all animals. I could obviously query the database, but my dilemma is how to best create the objects which have both properties and methods. In your animal case the factory would take some sort of data to identify what type of animal needs to be constructed and then do so accordingly. That might be an ID which is then looked up in the database or it might be an array with a specific member key. It might also be two separate arguments, one for the type and another for the context. The main purpose is to offload the construction to a central place, similar to how dependency injection makes the container responsible for construction of objects. Your factory might start out as simple as something like: public function getById($id){ $data = $this->lookupIdInDb($id); $class = $data['class']; return new $class($data); } Yes, it is a primary key as I explained in response to requinix. My question is where to offload it: whether in a single factory classes which is only responsible to creates objects for all types, or in one of the parent classes. The problem with the parent class is it needs to extend and execute the animals class twice. Quote Link to comment Share on other sites More sharing options...
kicken Posted January 10, 2017 Share Posted January 10, 2017 My question is where to offload it: whether in a single factory classes which is only responsible to creates objects for all types, or in one of the parent classes. Put it into it's own separate class. class AnimalFactory { public function create($id){ //do stuff... return $animal; } } Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted January 10, 2017 Author Share Posted January 10, 2017 Put it into it's own separate class. Will do. I had put multiple create methods in a single class, but agree separate classes is much better. I take it I want to make the class as low level as possible (i.e. don't use MammalFactory and ReptileFactory) providing that the method name is generic (i.e. create(), and not like I am doing below). class Factory { public function createAnimal($id){ //do stuff... return $animal; } public function createPlant($id){ //do stuff... return $plant; } } Also, is a factory class a good application for a static class? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.