Multiple object instantiation prevention? - php

I have a class with a private variable used to store an object.
I have a function that checks first if that variable already contains an object or not; if not, it instantiates the needed object and sets it to that variable, otherwise it just returns the content of that variable.
I was wondering if the getSessionCustomer() here is an overkill/unnecessary or if it has real benefits. I simply based this on the Album tutorial by Zend, but I haven't been able to fully test it out yet to really see the advantages (or disadvantages). As far as I know it wasn't explained in the docs why this additional function was included.
class JobController extends AbstractActionController
{
private $SessionCustomer;
public function saveJobAction()
{
$SessionCustomer = $this->getSessionCustomer();
if(empty($SessionCustomer->offsetGet('customer_id'))) {
return $this->redirect()->toRoute('login');
} else {
$JobService = $this->getServiceLocator()->get('Job\Factory\JobServiceFactory');
$job_id = $JobService->saveJob();
return $this->redirect()->toUrl('/job/' . $job_id);
}
}
public function viewJobAction()
{
$sm = $this->getServiceLocator();
$SessionCustomer = $this->getSessionCustomer();
if(empty($SessionCustomer->offsetGet('customer_id'))) {
return $this->redirect()->toRoute('login');
} else {
$JobTable = $sm->get('Job\Model\JobTable');
$JobItemTable = $sm->get('Job\Model\JobItemTable');
$jobId = $this->params()->fromRoute('id');
$Job = $JobTable->getJobById($jobId);
$JobItems = $JobItemTable->getJobItemsByJobId($jobId);
$this->layout()->setVariable('title', 'Order #' . $jobId);
$viewModel = new ViewModel();
$viewModel->setVariables(array(
'Job' => $Job,
'JobItems' => $JobItems
));
return $viewModel;
}
}
private function getSessionCustomer()
{
if(!$this->SessionCustomer) {
$this->SessionCustomer = $this->getServiceLocator()->get('Session\Customer');
}
return $this->SessionCustomer;
}
}

I don't think its an overkill, but I usually avoid calling getServiceLocator() in Controllers.
What you are asking about is basically making sure that the controller's dependency requirement is met. You can use a Factory for the same purpose and do this more sophisticated way. You can create a factory and inject the dependencies directly into the controller. This you will never make a call to the non-object variables.
For that you will be required to create a class that implements a FactoryInterface which will have a method createService which will provide you with ServiceLocator. You can use that serviceLocator to get all the dependencies and inject them directly into your Class.

Related

How can I decouple instantiation from implementation for unit testing if DI is not feasible?

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.

PHP/OOP - Using parent class to run child functions

I'm looking for a way to have a single base class that can be extended by several child classes, only one of which would be active at a time. A very basic example:
class API_Base {
public $context;
public function __construct() {
$this->init()
}
}
class Mailchimp_API extends API_Base {
public function init() {
$this->context = 'mailchimp';
$this->enabled = false;
}
public function add_contact($email_address) {
// mailchimp API for adding contact
}
}
class Infusionsoft_API extends API_Base {
public function init() {
$this->context = 'infusionsoft';
$this->enabled = true;
}
public function add_contact($email_address) {
// infusionsoft API for adding contact
}
}
Each child initializes itself and registers as an option for the user to select. After the user has chosen which integration to use, this is saved to the database. I'd like future access to the API_Base to look something like:
$api = new API_Base();
$api->context; // should be "infusionsoft"
$api->add_contact($email_address);
So when $api->add_contact() is run, it only runs the add_contact() function for the active API integration.
Eventually I'd like to somehow use get_class_methods(); to return the capabilities of just the active API, so functions accessing the API can know what is possible (i.e. some API's support email lists while others don't, or support creating custom fields, etc.).
I've had some success with calling parent::set_context($context); from the enabled class, but I still can't figure out how to get the parent to only execute the methods in the "enabled" child class.
This is not how inheritance works. Child subclasses inherit from their parent class.
To solve your problem you can add a factory method to API_Base which will create API implementation by its type:
class API_Base {
public static function createByType($type)
{
switch ($type) {
case 'mailchimp': return new Mailchimp_API();
case 'infusionsoft': return new Infusionsoft_API();
default: throw new \InvalidArgumentException(spintf('Invalid API type "%s"', $type));
}
}
// other methods
}
and use it like this:
$api = API_Base::createByType($user->selectedApi);
$api->context; // should be "infusionsoft"
$api->add_contact($email_address);
You can consider Abstract Class Implementation . The abstract class works as the , who ever is extending the abstract class can execute the methods it have .
abstract class Something{
function __construct(){
// some stuff
}
function my_func(){
$this->myTest ;
}
abstract function my_func();
}
class Some extends Something{
function __construct(){
parent::__construct() ;
}
function my_test(){
echo "Voila" ;
}
}
I got it working in a way works perfectly for me, thanks to Ihor's advice. Here's what I ended up doing:
In the main plugin file, there's a filterable function where other devs can add new integrations if they need. The first parameter is the slug (for my autoloader) and the second is the class name.
public function get_apis() {
return apply_filters( 'custom_apis', array(
'infusionsoft-isdk' => 'MYPLUGIN_Infusionsoft_iSDK',
'infusionsoft-oauth' => 'MYPLUGIN_Infusionsoft_oAuth',
'activecampaign' => 'MYPLUGIN_ActiveCampaign'
) );
}
Each integration contains the slug and the class name. Then in my API_Base class I have this in the constructor:
class API_Base {
public $available_apis = array();
public $api;
public function __construct() {
$configured_apis = main_plugin()->get_apis();
foreach( $configured_apis as $slug => $classname ) {
if(class_exists($classname)) {
$api = new $classname();
$api->init();
if($api->active == true)
$this->api = $api;
$this->available_apis[$slug] = array( 'name' => $api->name );
if(isset($api->menu_name)) {
$this->available_apis[$slug]['menu_name'] = $api->menu_name;
} else {
$this->available_apis[$slug]['menu_name'] = $api->name;
}
}
}
}
}
And in my main file, after all the includes, I run:
self::$instance->api_base = new API_Base();
self::$instance->api = self::$instance->api_base->api;
Now I can call self::$instance->api->add_contact($email); and it will trigger whichever is the current active API.
It seems to be the best approach as this way I can spin up the API only once when the plugin loads, instead of having to create a new instance each time I want to use it.

Return different objects based on conditional argument

I need help with some code desiging. I have a package which is used in many projects.
$p = new Package();
$result = $p->method();
While the Package looks like:
class Package {
public function method($fooArg = 1, $barArg = 1)
{
// some logic
return new SomeClass(
$fizzArg,
$buzzArg
);
}
}
Now, in one project which is using Package I need to change returned class. So, the call will look like this:
$p = new Package();
$result = $p->method(10, 10, true);
And the Package will look like this:
class Package {
public function method($fooArg = 1, $barArg = 1, $condArg = false)
{
// some logic
if (false === $condArg) {
return new SomeClass(
$fizzArg,
$buzzArg
);
}
return new MyNewClass(
$fizzArg,
$fooBarArg
);
}
}
Which design pattern should be used here? I do not want to return different object types based on condition, because it seems very ugly to me.
Since you explicitly set $condArg from the calling script and it is the only argument that control which instance to return, consider to create a second public method to return MyNewClass, and extract some logic into private method to share it between 2 public methods:
class Package {
public function method($fooArg = 1, $barArg = 1)
{
list $fizzArg, $fooBarArg = $this->someLogic($fooArg, $barArg);
return new SomeClass(
$fizzArg,
$buzzArg
);
}
public function newMethod($fooArg = 1, $barArg = 1)
{
list $fizzArg, $fooBarArg = $this->someLogic($fooArg, $barArg);
return new MyNewClass(
$fizzArg,
$fooBarArg
);
}
protected function someLogic($fooArg, $barArg)
{
// some logic
return [
$fizzArg,
$fooBarArg
]
}
}
This could be resolved with a combination of the Factory and Dependency Injection patterns:
The example below is a bit long winded, but it illustrates the basic principle. By providing your Package class with a factory implemented by the specific project. You don't need to change the code of that class. Instead, the changes are made with abstractions via interfaces.
/*
* Shared library
*/
interface IEntity
{
}
interface IFactory
{
/**
* #param $arg1
* #param $arg2
* #return IEntity
*/
public function create($arg1, $arg2);
}
class Package
{
protected $factory;
public function __construct(IFactory $factory)
{
$this->factory = $factory;
}
public function method($arg1, $arg2)
{
return new $this->factory->create($arg1, $arg2);
}
}
/*
* Project A
*/
class FactoryA implements IFactory
{
public function create($arg1, $arg2)
{
return new EntityA();
}
}
class EntityA implements IEntity
{
public function construct($arg1, $arg2)
{
}
}
/*
* Project B
*/
class FactoryB implements IFactory
{
public function create($arg1, $arg2)
{
return new EntityB();
}
}
class EntityB implements IEntity
{
public function construct($arg1, $arg2)
{
}
}
From a purely theoretical point of view, the very idea to use such a package that has to return something else based on where it is used is very ugly. This way it means that the widely-used package depends on a details of the package that uses it and this to me is a signal that you have to scrap the idea entirely and not use this package in this one project.
Your Package seems like a Factory method, it builds objects according to parameters. If I get it right, now you want to have different Packages for different projects with different objects.
Well Abstract factory is what you are looking for.
Make your Package abstract. Have two implementations, and load the proper package in the initiation phase you can use reflection or configuration or whatever PHP lets you do.
Note: It seems that there is some other logic in your Package class, if that logic is independent of building objects extract it to a different class, or vise versa.
since you don't have access to all project using Package, and you can change the source of Package if it does not affect other projects, then it is safer to create a descendant of Package instead. this way, you can change existing methods without affecting other projects, and you can also add new methods.
include('package.php');
class myPackage extends Package(){
public function newMethod($arg1, $arg2){
return new otherClass($arg1, $arg2);
}
//if you want to change existing method
public function method($fooArg = 1, $barArg = 1){
//some new logic
}
}
then you can use it in your project:
$obj = new myPackage();
if ($i_want_regular_class){
$newObj = $obj->method(1, 2); // call parent's method or modified parent's method
} else {
$newObj = $obj->newMethod(3, 4); // call new method
}
as for why i suggest you to create new method is because you already know which object you want to create, hence the argument passed to the method. so instead of putting the conditional in the method, why not put the conditional in the logic and call the appropriate method?

Instantiating class with many parameters

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.

Modular design pattern

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];
}
}

Categories