Php, is it OK to use traits for DI? - php

consider this example:
class MyClass
{
public function doSomething()
{
$this->injected->getIt();
}
}
so far so simple (apart from injected is not injected). So, in full version:
class MyClass
{
/**
* #var Injected
*/
private $injected;
public function __constructor(Injected $injected)
{
$this->injected = $injected;
}
public function doSomething()
{
$this->injected->getIt();
}
}
but I find it enoromous. Why to pollute my class with tons of code of DI? Lets split this into two entities:
trait MyClassTrait
{
/**
* #var Injected
*/
private $injected;
public function __constructor(Injected $injected)
{
$this->injected = $injected;
}
}
class MyClass
{
use MyClassTrait;
public function doSomething()
{
$this->injected->getIt();
}
}
its much nicer although I never seen anybody using it like this. Is it a good approach?

For example like this:
<?php
class Factory
{
private $services = [];
public function __construct() {
$this->services[self::class] = $this;
}
public function getByType($type){
if(isset($services[$type])){
return $services[$type];
}
if(class_exists($type)){
$reflection = new ReflectionClass($type);
$constructor = $reflection->getConstructor();
$parameters = [];
if($constructor)
foreach($constructor->getParameters() as $parameter){
if($parameter->getClass()) {
$parameters[] = $this->getByType($parameter->getClass()->name);
} else if($parameter->isDefaultValueAvailable()){
$parameters[] = $parameter->getDefaultValue();
}
}
return $services[$type] = $reflection->newInstanceArgs($parameters);
} // else throw Exception...
}
}
abstract class DI
{
public function __construct(Factory $factory) {
$reflection = new ReflectionClass(get_class($this));
foreach($reflection->getProperties() as $property){
preg_match('/#var ([^ ]+) #inject/', $property->getDocComment(), $annotation);
if($annotation){
$className = $annotation[1];
if(class_exists($className)){
$property->setAccessible(true);
$property->setValue($this, $factory->getByType($className));
} // else throw Exception...
}
}
}
}
class Injected
{
public function getIt($string){
echo $string.'<br />';
}
}
class DIByConstructor
{
/** #var Injected */
private $byConstructor;
public function __construct(Injected $injected) {
$this->byConstructor = $injected;
}
public function doSomething()
{
echo 'Class: '.self::class.'<br />';
$this->byConstructor->getIt('By Constructor');
echo '<br />';
}
}
class DIByAnnotation extends DI
{
/** #var Injected #inject */
private $byAnnotation;
public function doSomething()
{
echo 'Class: '.self::class.'<br />';
$this->byAnnotation->getIt('By Annotation');
echo '<br />';
}
}
class DIBothMethods extends DI
{
/** #var Injected */
private $byConstructor;
/** #var Injected #inject */
private $byAnnotation;
public function __construct(Factory $factory, Injected $injected) {
parent::__construct($factory);
$this->byConstructor = $injected;
}
public function doSomething()
{
echo 'Class: '.self::class.'<br />';
$this->byConstructor->getIt('By Constructor');
$this->byAnnotation->getIt('By Annotation');
echo '<br />';
}
}
$factory = new Factory();
$DIByConstructor = $factory->getByType('DIByConstructor');
$DIByConstructor->doSomething();
$DIByAnnotation = $factory->getByType('DIByAnnotation');
$DIByAnnotation->doSomething();
$DIBothMethods = $factory->getByType('DIBothMethods');
$DIBothMethods->doSomething();

Note that with #Kazz approaching (DI by Annotations) you cannot reference an Interface, instead you are referencing a Class. So this is good for fast instantiating with almost zero verbose but at the end, you are loosing all the DI potential.

Related

PHP: How to make a function accept a single object which can be of different classes based on the call or user input?

Okay, here is my print_details function
class Vehicle{
//constructor goes here
public function print_details(//one object as parameter)
{
echo "\nName : $this->name";
echo "\nDescription: $this->desc \n";
if(strnatcasecmp(get_class($this),"Car")==0)
{
$this->getCarDetails();
}
elseif (strnatcasecmp(get_class($this),"Bus")==0)
{
$this->getBusDetails();
}
}
}
I intend to use only one object as a parameter, which can be of either class Car or Bus. But it should call the appropriate function based on the class of the object.
Is it possible to do it? If yes,how?
I would suggest you to use the following class structures:
abstract class Vehicle {
protected $name;
protected $desc;
abstract public function getDetails();
//constructor goes here
public function print_details()
{
echo "Name : $this->name", PHP_EOL;
echo "Description: $this->desc", PHP_EOL;
foreach ($this->getDetails() as $key => $value) {
echo "{$key}: {$value}", PHP_EOL;
}
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getDesc()
{
return $this->desc;
}
public function setDesc($desc)
{
$this->desc = $desc;
}
}
class Car extends Vehicle {
protected $type;
public function getType()
{
return $this->type;
}
public function setType($type)
{
$this->type = $type;
}
public function getDetails()
{
return [
'Type' => $this->type
];
}
}
class Bus extends Vehicle {
protected $numberOfSeats;
/**
* #return mixed
*/
public function getNumberOfSeats()
{
return $this->numberOfSeats;
}
/**
* #param mixed $numberOfSeats
*/
public function setNumberOfSeats($numberOfSeats)
{
$this->numberOfSeats = $numberOfSeats;
}
public function getDetails()
{
return [
'Number of seats' => $this->numberOfSeats
];
}
}
$car = new Car();
$car->setName('BMW');
$car->setDesc('Car description');
$car->setType('sedan');
$car->print_details();
$car = new Bus();
$car->setName('Mers');
$car->setDesc('Bus description');
$car->setNumberOfSeats(20);
$car->print_details();

Is it bad practice to include variable which must be initialised by subclass constructor in PHP?

I've been doing a lot of reading on constructors and initialising variables, and I've came across a problem which I'm trying to solve. I'm trying to solve the lack of generics support by introducing a variable that needs to be initialised by the subclass.
<?php
abstract class Collection_Base {
protected $typeOf; // Must be initialised by the subclass
protected $collection = array();
}
class Cookie_Collection extends Collection_Base {
protected $typeOf = 'System\Web\Http_Cookie';
public function set ($item) {
if (!$item instanceof $this->typeOf) {
throw new \InvalidArgumentException;
}
$this->collection[] = $item;
}
}
?>
So I was wondering, is it bad practice to include variable which must be initialised by subclass constructor in PHP? Is there anything I need to be aware of when doing so?
While not directly related, I've used the following sources to gather my information:
http://docs.hhvm.com/manual/en/hack.otherrulesandfeatures.classinitialization.php
http://ralphschindler.com/2012/03/09/php-constructor-best-practices-and-the-prototype-pattern
SOLUTION
<?php
abstract class Collection_Base {
protected $collection = array();
public abstract function getType();
private function getTypeInternal () {
$type = $this->getType();
if (is_class($type)) {
throw new \UnexpectedValueException;
}
return $type;
}
public function set ($item) {
$type = $this->getTypeInternal();
if (!$item instanceof $type) {
throw new \InvalidArgumentException;
}
$this->collection[] = $item;
}
}
class Cookie_Collection extends Collection_Base {
protected $type = 'System\Web\Http_Cookie';
public function getType () {
return $this->type;
}
}
?>
I thought I recognized this as an anti-pattern, so I looked for where I read about it, but then I remembered it was this: http://en.wikipedia.org/wiki/Call_super, which isn't quite the same thing.
On to what you are doing however. There are a lot of similar libraries which use a practice like this, however they differ by enforcing the practice in way of abstract methods:
abstract class Collection_Base {
protected $typeOf;
protected $collection = array();
/**
* #return string
*/
public function getType()
{
if (null === $this->typeOf) {
$this->typeOf = $this->doGetType();
}
return $this->typeOf;
}
/**
* #return string
*/
abstract protected function doGetType();
}
class Cookie_Collection extends Collection_Base {
/**
* #param $item
*/
public function set ($item) {
if (!$item instanceof $this->getType()) {
throw new \InvalidArgumentException;
}
$this->collection[] = $item;
}
/**
* #inheritdoc
*/
protected function doGetType()
{
return 'System\Configuration\Configuration_Element';
}
}
Use a Factory pattern to hide constructor details ... see http://www.phptherightway.com/pages/Design-Patterns.html
Make Collection_Base an abstract class and define a method that returns appropriate class name:
abstract class Collection_Base
{
protected $collection = [];
public function add($item)
{
if (!$item instanceof $this->getType()) {
throw new \InvalidArgumentException();
}
$this->collection[] = $item;
}
abstract protected function getType();
}
class Collection_Cookie extends Collection_Base
{
protected function getType()
{
return Configuration_Element::class;
}
}
Using this approach it's not possible for other developers to forget about type "property".
EDIT:
Using a factory, as suggested by Luca Rocchi is also a very good idea.

Symfony2 structural composite pattern with entities

I am trying to implement a simple menu composite pattern.
These are the following classes i came up with.
MenuItem:
namespace MYNAME\MYBUNDLE\Entity;
use MYNAME\MYBUNDLE\Menu\MenuComponent;
class MenuItem implements MenuComponent
{
private $id;
private $name;
private $path;
private $parent;
private $visible;
private $createdOn;
private $templating;
private $attr;
private $children;
private $website;
private $position = 1;
public function __construct($name = null, $path = null, $attr = array(), $visible = true)
{
$this->name = $name;
$this->path = $path;
$this->visible = $visible;
$this->attr = $attr;
$this->createdOn = new \DateTime;
}
public function prePersist()
{
$this->createdOn = new \DateTime;
}
public function build()
{
$data['menu_item'] = $this;
$data['options'] = $this->attr;
if($this->hasChildren())
return $this->templating->render('MYBUNDLE:Menu:menu_dropdown.html.twig', $data);
if($this->isChild())
return $this->parent->getTemplating()->render('MYBUNDLE:Menu:menu_item.html.twig', $data);
return $this->templating->render('MYBUNDLE:Menu:menu_item.html.twig', $data);
}
public function __toString()
{
return $this->name;
}
public function setTemplating($templating)
{
$this->templating = $templating;
}
/**
* #return bool
*/
public function isChild()
{
return $this->hasParent();
}
/**
* #return bool
*/
public function hasParent()
{
return isset($this->parent);
}
/**
* #return bool
*/
public function hasChildren()
{
return count($this->children) > 0;
}
}
If left out the getters and setters to make it a bit shorter here.
As you can see this is the entity and it contains a build() function, however this function uses the render method which in my opinion shouldn't be in an entity.
MenuController
<?php
namespace MYNAME\MYBUNDLE\Controller;
use MYNAME\MYBUNDLE\Menu\Menu;
use MYNAME\MYBUNDLE\Entity\MenuItem;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class MenuController extends Controller
{
public function generateAction()
{
$menu = new Menu($this->get('templating'));
// load menu items
$items = $this->getDoctrine()->getRepository('MYBUNDLE:MenuItem')->findOrdered();
foreach($items as $item)
{
if(!$item->hasParent())
$menu->add($item);
}
return new Response($menu->build());
}
}
The MenuController gets called to render the menu:
{{ render(controller('MYBUNDLE:Menu:generate')) }}
I would also like this to be different since it doesn't look right. Perhaps it's better to create a twig function to render the menu?
MenuComponent:
namespace MYNAME\MYBUNDLE\Menu;
interface MenuComponent {
public function build();
}
Menu:
namespace MYNAME\MYBUNDLE\Menu;
class Menu implements MenuComponent
{
private $children;
private $templating;
public function __construct($templating)
{
$this->templating = $templating;
}
public function add(MenuComponent $component)
{
$component->setTemplating($this->templating);
$this->children[] = $component;
}
public function build()
{
return $this->templating->render('MYBUNDLE:Menu:menu.html.twig', array("menu_items" => $this->children));
}
}
Menu Contains the MenuComponents and will render the menu first, in each MenuItem it's build() method is called.
I think it's better to remove the rendering logic from my MenuItem entity and place this somewhere else, however i can't figure out on how to do this properly within this design pattern.
Any help or suggestion is appreciated.

Serialization of 'Closure' is not allowed with php pthreads

I need little help with pthreads in php. I have following class
namespace le\Thread;
class Thread extends \Thread
{
protected $method;
protected $params;
protected $result = null;
protected $joined = false;
/**
* Provide a passthrough to call_user_func_array
**/
public function __construct($method, $params)
{
$this->method = $method;
$this->params = $params;
}
/**
* The smallest thread in the world
**/
public function run()
{
if (($this->result = call_user_func_array($this->method, $this->params))) {
return true;
} else {
return false;
}
}
/**
* Static method to create your threads from functions ...
**/
public static function process($method, $params)
{
$thread = new self($method, $params);
if ($thread->start()) {
return $thread;
}
/** else throw Nastyness **/
}
/**
* Do whatever, result stored in $this->result, don't try to join twice
**/
public function getResult()
{
if (!$this->joined) {
$this->joined = true;
$this->join();
}
return $this->result;
}
}
and I want to use it this way. In another class I have CPU heavy method which I want to process multithreaded.
$thread = Thread::process([$this, 'method'], $dataArray);
$thread->getResult();
but It throws following error
Serialization of 'Closure' is not allowed
How can I fix that? Is that even possible?

How to access variable of one class from other class?

I have situation like this:
// Object Class
class Person_Object {
protected $_id;
public function __construct( $id = null ) {
$this->_id = $id;
}
public function getMapper() {
$mapper = new Person_Mapper();
return $mapper;
}
public function printIdInMapper() {
$this->getMapper()->printIdInMapper();
}
}
// Mapper Class
class Person_Mapper {
public function printIdInMapper() {
// How to access Person_Object's id here and echo id?
}
}
// Code
$personModel = new Person_Object(10);
$personModel->printIdInMapper(); // should print 10
Now how to echo Person_Object's id value 10 in printIdInMapper() function here
Try this:
// Object Class
class Person_Object {
protected $_id;
public function __construct( $id = null ) {
$this->_id = $id;
}
public function getId() {
return $this->_id;
}
public function getMapper() {
$mapper = new Person_Mapper($this);
return $mapper;
}
public function printIdInMapper() {
$this->getMapper()->printIdInMapper();
}
}
// Mapper Class
class Person_Mapper {
$_person
public function __construct( $person ) {
$this->_person = $person
}
public function printIdInMapper() {
echo $this->_person->getId();
}
}
A slightly different approach:
class Person_Object {
protected $_id;
public function __construct( $id = null ) {
$this->_id = $id;
}
public function getId() {
return $this->_id;
}
public function getMapper() {
$mapper = new Person_Mapper();
$mapper->setPerson($this);
return $mapper;
}
public function printIdInMapper() {
$this->getMapper()->printIdInMapper();
}
}
// Mapper Class
class Person_Mapper {
protected $person;
public function setPerson(Person_Object $person) {
$this->person = $person;
}
public function getPerson() {
return $this->person;
}
public function printIdInMapper() {
echo $this->getPerson()->getId();
}
}

Categories