Dependency Injection in PHP using pimple - php

I'm new to DI ,using Pimple. Using: php 5.3.5 (wamp), namespaces as well.
I'm refactoring code, using it, but came to a problem (s):
I have my Container that extends from Pimple, lets call it PContainer.php:
class ReuseableContainer extends Pimple{
private function initOutterClass(){
$this['special_location_class'] = '\SpecialLocation';
$this['special_location'] = function($c){return new $c['special_location_class']($c['location_details'],$c['location']);};
}
private function initGlobalFunctions(){
$this['getGeneralDataFromArray'] = function($c){
// returning a function
return function($arr){
foreach ($arr as $key => $value){
// do something
$new_data = $c['general_data_type'];
$new_data->id = $value['id'];
$new_data->name = $value['name'];
}
}
}
public function __construct(){
$this['location_class'] = '\Location';
$this['location_details_class'] = '\LocationDetails';
$this['general_data_type_class'] = '\GeneralDataType';
// define some objects
$this['location'] = function ($c) {
return new $c['location_class']();
};
$this['location_details'] = function ($c) {
return new $c['location_details_class']();
};
$this['general_data_type'] = function ($c) {
return new $c['general_data_type_class']();
};
$this->initOutterClass();
$this->initGlobalFunctions();
}
}
global $container ;
$container = new Pimple();
// embed the SomeContainer container
$container['embed'] = $container->share(function () { return new ReuseableContainer(); });
Ok. So i got a SpecialHelper.php which holds:
final class SpecialLocation{
public $name;
public $location;
public $picture;
public function __construct($location){
$this->location; // dependent on class: Location
}
}
final class SpecialUser{
private $id;
private $location;
public function __construct(\Location $location,$id=''){
$this->id = $id;
$this->location = $location; // $container['embed']['location'];
}
and we got our GeneralHelper.php which holds:
final class Location{
public $lat;
public $lng;
public function __construct($lat='',$lng=''){ $this->lat = $lat; $this->lng = $lng;}
}
final class LocationDetails{
public $id;
public $addresss;
public function __construct($id='',$address=''){$this->id = $id; $this->address = $address;}
}
class GeneralDataType{
public $id;
public $name;
public function getName(){ return $this->name;}
public function getId(){ return $this->id;}
}
and we have our "Special Class" controller, which looks something like this:
final class SpecialController{
public function foor($some_array){
$this->doSomething($some_array);
}
private function doSomething($ret_value){
// do something
$arr = array();
foreach($ret_value as $key => $value){
$something = $container['embed']['getGeneralDataFromArray']($value);
$special_location = $container['embed']['special_location'];
$arr[] = special_location;
}
return $arr;
}
}
Finally we have our main "driver", main.php
require('PContainer.php');
....
...
$some_array = array(....);
$special_controller = new SpecialController();
$special_controller->foor($some_array);
Problems:
1) I had to add initOutterClass function inside ReuseableContainer to decouple the "Special" classes, how could have i decoupled them in a better way? creating a new "special" 9container or something? as EVERYTHING now sitts inside the container.. same goes to the initGlobalFunctions()
2) regarding SpecialHelper.php: i have there SpecialLocation, which one of its properties is a \Location class, i've put it in the constructor , but if i have 20 object properties that are dependent, i must put them all as INPUT params for the constructor?? same goes to the SpecialUser class, it has a $location which if i could i would have made $this->location = $container['embed']['location']; instead of $this->location = $location; resulting in a dependent on the DI! :/
3) I've had to create SpecialHelper.php in a different file, despite wanting to put it in the "special class controller", just so there won't be any unknowns (due to require statement order)
4) MOST importantly: about the "Special class" controller, how do i solve the doSomething method? i must create "Special Location" object inside the loop but i get that $container is unrecognized (despite being global, as of scope probably) but more over it's really dependent! and it's a private function, i don't wish to pass the container to EVERY class i'll use from now on, it isn't IoC right?
Any help is appriciated... i'm trying to understand the best practices..
Thank you

4)Most important: IoC is correct. That an implementation is not correctly working does not reflect the principle of IoC itself.
If you want to use the global $container within a function, then should you use the global keyword within that function. That is how PHP works. Making it static is solving the problem of reference, but does not make a real difference.
An IoC container resolves the dependencies for the caller. The caller does not have to know anything about the internals of the callee - and he doesn't care either. So, there should be some kind of contract by which the exchange of data is regulated. If you have that situation, then you have IoC.
3)That problem is too vague to answer, but imo also not relevant from a practical perspective. Does it work? Ok, good to know. :-)
2)The clue of IoC is the use of contracts. The IoC container is there to connect the caller to the proper contract. The contract resolves to a concrete callee. The callee will return information inline with the contract. The caller understands the answer. Therefor will you need that the input and output in this process is independent of a certain implementation at a certain time. So don't use 20 object properties as input, but use an array or general object instead.
1) I get the idea that you are mixing functional flow (data flow) with technical flow (relationships between classes). An IoC container serves the purpose of the technical flow, it optimizes the dependency in the relationships between classes. For instance, if you want to connect to a database, then might you reuse an existing connection instead of creating new connections all the time. Or if you want to use a special functionality on several moments in your flow, then might you use IoC for that.

Related

PHP OOP - Pass data between classes through the calling class?

I'm struggling to find a correct approach to pass data between classes, which do not directly call each other, and are only related through a parent class (which I now use, but I consider it a dirty workaround rather than anything near a solution).
I have 3 classes both able to read input and write output, and based on configuration I set one to read, another one to write. It may even be the same class, they all share a parent class, but they are always two separate instances called from a controller class.
Currently I use this sort of functionality:
class daddy {
public static $data;
}
class son extends daddy {
public function setData() {
parent::$data = "candy";
}
}
class daughter extends daddy {
public function getData() {
echo parent::$data;
}
}
while($processALineFromConfig)
$son = new son;
$son->setData();
$daughter = new daughter;
$daughter->getData();
daddy::$data = null; //reset the data, in the actual code $daughter does that in parent::
}
Instantination of these classes runs in a loop, therefore I always need to reset the data after $daughter receives them, 'cos otherwise it would stay there for another pass through the loop.
I'm absolutely sure it's not how class inheritance is supposed to be used, however I'm struggling to find a real solution. It only makes sense the data should be stored in the controller which calls these classes, not the parent, but I already use return values in the setter and getter functions, and I am not passing a variable by reference to store it there to these functions 'cos I have optional parameters there and I'm trying to keep the code clean.
What would be the correct approach to pass data through the controller then?
Thanks!
The best option would be for two object share some other, third object. This would be the class for "third object" which will ensure the exchage:
class Messenger
{
private $data;
public function store($value)
{
$this->data = $value;
}
public function fetch()
{
return $this->data;
}
}
Then a class for both instance, that will need to share some state:
class FooBar
{
private $messenger;
private $name = 'Nobody';
public function __construct($messenger, $name)
{
$this->messenger = messenger;
$this->name = $name;
}
public function setSharedParam($value)
{
$this->messenger->store($value);
}
public function getSharedParameter()
{
return $this->name . ': ' . $this->messenger->fetch();
}
}
You utilize the classes like this:
$conduit = new Messenger;
$john = new FooBar($conduit, 'Crichton');
$dominar = new FooBar($conduit, 'Rygel');
$dominar->setSharedParameter('crackers');
echo $john->getSharedParameter();
// Crichton: crackers
Basically, they both are accessing the same object. This also can be further expanded by making both instance to observe the instance of Messenger.

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.

PHP Dependency Injection and Loose Coupling

I am pondering a few different approaches here and would really appreciate some input! I am considering the two choices below. There are 2 things going on there I have questions on.
Is it preferred to inject the dependencies into the constructor of the main "container" class, or to instead create new instances inside the container class?
In the second example, the class' dependencies are injected via constructor and then maintained within via a property of the class. Then when the methods (route(), render()) are called, the dependencies are called from within. I began with this approach, but am now favoring something more along the lines of the first example. I think the first example is preferable, but are there any benefits to using the DI approach in the second example?
There really is no need to store anything in the class as a property. I can probably rearrange everything to use that technique without much trouble, and I think I like it better. This way I can also move all of the of work out of the constructors, and simply access everything via method later. Am I on the right track here?
class App
{
private $config;
private $router;
private $renderer;
public function __construct(IConfig $config, IRouter $router, IRenderer $renderer)
{
$this->config = $config;
$this->router = $router;
$this->renderer = $renderer;
$this->run();
}
public function run()
{
$data = $this->router->route(new Request, $config->routes);
$this->renderer->render($data);
}
}
class App
{
private $config;
private $router;
private $renderer;
public function __construct()
{
$this->config = new Config;
$this->run();
}
public function run()
{
$this->router = new Router(new Request, $config->routes);
$this->router->route();
$this->renderer = new Renderer($this->router->getData());
$this->renderer->render();
}
}
It is better to inject dependencies into the constructor.
Creating instances within the constructor creates a tight coupling between the two classes. With a constructor with a clear signature like
public function __construct(IConfig $config, IRouter $router, IRenderer $renderer)
I can immediately tell what this component needs to do it's job.
Given a constructor like
public function __construct();
There is no clue what the component needs to function. It creates a strong coupling to specific implementations of your each your router, your request and to your renderer, none of which are apparent until you dig down into the guts of your class.
In summary the first approach is well documented, extendable and testable.
the second approach is opaque, highly coupled, and not easily testable.
While Orangepill makes a good point, I thought I'd chip in, too. I tend to define my constructors with a clear constructor, too, but I don't expect the required objects to be passed when creating an instance.
Sometimes, you create an instance that retrieves data either from a DB, or some sort of Http request. In your case, the first example expects three dependencies to be passed, but who's to say that you'll always need all three of them?
Enter Lazy-Loading. The code sample below is quite lengthy, but it is (IMO) well worth looking into. If I use a service, I don't want to load all dependancies unless I'm sure I'll be using them. That's why I defined the constructor so that I can create an instance in either one of the following ways:
$foo = new MyService($configObj);
$bar = new MyService($configObj, null, $dbObj);//don't load curl (yet)
$baz = new MyService($configObj, $curlObj);//don't load db (yet)
If I wanted to run some test, I can still inject the dependencies when constructing my instance, or I can rely on a test-config object or I could use the setDb and setCurl methods, too:
$foo->setCurl($testCurl);
Sticking to the first way of constructing the instance, I can safely say that, if I only invoke the getViaCurl method, the Db class will never be loaded.
The getViaDb method is a bit more elaborate (as is the getDb method). I don't recommend you working with methods like that, but it's just to show you how flexible this approach can be. I can pass an array of parameters to the getViaDb method, which can contain a custom connection. I can also pass a boolean that'll control what I do with that connection (use it for just this one call, or assign the connection to the MyService instance.
I hope this isn't too unclear, but I am rather tired, so I'm not all too good at explaining this stuff ATM.
Here's the code, anyway... it should be pretty self explanatory.
class MyService
{
private $curl = null;
private $db = null;
private $conf = null;
public function __construct(Config $configObj, Curl $curlObj = null, Db $dbObj = null)
{
$this->conf = $configObj;//you'll see why I do need this in a minute
$this->curl = $curlObj;//might be null
$this->db = $dbObj;
}
public function getViaCurl(Something $useful)
{
$curl = $this->getCurl();//<-- this is where the magic happens
return $curl->request($useful);
}
public function getViaDb(array $params)
{
if (isset($params['custom']))
{
$db = $this->getDb($params['custom'], $params['switch']);
}
else
{//default
$db = $this->getDb();
}
return $db->query($params['request']);
}
public function getCurl()
{//return current Curl, or load default if none set
if ($this->curl === null)
{//fallback to default from $this->conf
$this->curl = new Curl($this->conf->getSection('CurlConf'));
}
return $this->curl;
}
public function setCurl(Curl $curlObj)
{//inject after instance is created here
if ($this->curl instanceof Curl)
{//close current connection
$this->curl->close();
}
$this->curl = $curlObj;
}
public function setDb(Db $dbObj)
{
if ($this->db instanceof Db)
{//commit & close
$this->db->commit();
$this->db->close();
}
$this->db = $dbObj;
}
//more elaborate, even:
public function getDb(Db $custom = null, $switch = false)
{
if ($custom && !!$swith === true)
{
$this->setDb($custom);
return $this->db;
}
if ($custom)
{//use custom Db, only this one time
return $custom;
}
if ($this->db === null)
{
$this->db = new Db($this->conf->getSection('Db'));
}
return $this->db;
}
}

Immutable objects in PHP?

Is it a good idea to create objects that cannot be changed in PHP?
For example a date object which has setter methods, but they will always return a new instance of the object (with the modified date).
Would these objects be confusing to other people that use the class, because in PHP you usually expect the object to change?
Example
$obj = new Object(2);
$x = $obj->add(5); // 7
$y = $obj->add(2); // 4
Immutable objects don't have setter methods. Period.
Everyone will expect a setXyz() method to have a void return type (or return nothing in loosely typed languages). If you do add setter methods to your immutable object it will confuse the hell out of people and lead to ugly bugs.
In my opinion objects should be immutable for value objects. Other than that it does not have much benefits unless you're sharing your object across your whole application.
There is some wrong answers here, an immutable object can have setters. Here's some implementation of immutable objects in PHP.
Example #1.
class ImmutableValueObject
{
private $val1;
private $val2;
public function __construct($val1, $val2)
{
$this->val1 = $val1;
$this->val2 = $val2;
}
public function getVal1()
{
return $this->val1;
}
public function getVal2()
{
return $this->val2;
}
}
As you can see once instantiated you cannot changed any value.
Example 2: with setters:
class ImmutableValueObject
{
private $val1;
private $val2;
public function __construct($val1, $val2)
{
$this->val1 = $val1;
$this->val2 = $val2;
}
public function getVal1()
{
return $this->val1;
}
public function withVal1($val1)
{
$copy = clone $this;
$copy->val1 = $val1;
return $copy; // here's the trick: you return a new instance!
}
public function getVal2()
{
return $this->val2;
}
public function withVal2($val2)
{
$copy = clone $this;
$copy->val2 = $val2;
return $copy;
}
}
There is several implementation possible and this is by no means an exclusive list. And remember that with Reflection there is always a way to get around that in PHP, so immutability is all in your head in the end!
It is also often good practice to put immutable objects as final.
EDIT:
changed setX for withX
added comment about final
An immutable object cannot be changed after its initial creation so having setter methods makes no sense as it goes against that base principle.
You could implement some workarounds to simulate immutability in PHP by manipulating class member visibility and overriding the magic __set() method but its not guaranteed immutable as immutability is not a feature of the PHP language.
I believe someone once wrote an extension to provide an immutable value type in PHP though so you could google for that.
Making object immutable in PHP is pretty easy. Here is an elegant and convenient approach.
All you need to do is to create the base abstract class with the specific __get() and __set() magic methods and extend this base class in the child object.
This is quite applicable if you use value objects (e.g. for DDD).
Here is the base class:
abstract class BaseValueObject
{
public function __get(string $propertyName)
{
return $this->$propertyName;
}
public function __set(string $propertyName, $value): void
{
throw new \Exception("Cannot set property {$propertyName}. The object is immutable.");
}
}
Now a child object (well, its class).
class CategoryVO extends BaseValueObject
{
public $id;
public $name;
public function __construct(array $data)
{
$this->id = $data['id'];
$this->name = $data['name'];
}
}
It would throw an exception at attempt to set some value. Basically it is immutable.
This is it.
Make as many immutable objects as you need. Create the new objects via constructor. Dispose them and re-create the new ones when needed (add a specific creator method if required, a static or an instance one, to the base class or to the extended one).
Yet such an object would conveniently expose all its properties as read-only (for some kind of serialization or the like), unlike if we would have made them private (but even though we could use JsonSerializable interface to make the serialization as flexible as we need with private properties or even more drastic transformations).
Finally one cannot mistakenly instantiate BaseValueObject as it is an abstract class. From all standpoints nice elegant solution.
I made a little trait avoiding using Reflection to ease the implementation of immutability: https://github.com/jclaveau/php-immutable-trait
Obviously, as it's not a language feature, it won't impeach mutation by magic but lighten the code of the mutators that must clone the current instance before being applied. Applied to Massimiliano's example it would produce
class ImmutableValueObject
{
use JClaveau\Traits\Immutable;
private $val1;
private $val2;
public function __construct($val1, $val2)
{
$this->val1 = $val1;
$this->val2 = $val2;
}
public function getVal1()
{
return $this->val1;
}
public function withVal1($val1)
{
// Just add these lines at the really beginning of methods supporting
// immutability ("setters" mostly)
if ($this->callOnCloneIfImmutable($result))
return $result;
// Write your method's body as if you weren't in an Immutable class
$this->val1 = $val1;
return $this;
}
public function getVal2()
{
return $this->val2;
}
public function withVal2($val2)
{
if ($this->callOnCloneIfImmutable($result))
return $result;
$this->val2 = $val2;
return $this;
}
}
You can see that you don't return $copy here but $this as Kanstantsin K noticed.
In native PHP https://secure.php.net/manual/en/class.datetimeimmutable.php has mutators that will return new instances with modification applied. So copy pasting sentences saying that immutable objects shouldn't have mutators doesn't seem super interesting.
The practice of using "withXXX" instead of "setXXX" is super interesting, thanks for the suggestion! I personnaly used "becomesXXX" for the api chainging the mutability of the instance (optionnal API in the trait SwitchableMutability).
Hoping it can help some people here!
PS: Suggestions on this little feature are really welcome :) : https://github.com/jclaveau/php-immutable-trait/issues
From an immutable object, you can get its values but there is no way to modify them. Here you can see an example of an immutable class:
<?php
declare(strict_types=1);
final class Immutable
{
/** #var string */
private $value;
public static function withValue(string $value): self
{
return new self($value);
}
public function __construct(string $value)
{
$this->value = $value;
}
public function value(): string
{
return $this->value;
}
}
// Example of usage:
$immutable = Immutable::withValue("my value");
$immutable->value();
If you want setters on a class and object this is perfectly fine, we do this all of the time as we need to set object data. Just simply don't call it immutable.
Many things in the dev world are subjective - our approaches, methodology etc - but "immutable" is a pretty solid definition:
"Immutable":
- Unchanging over time or unable to be changed.
If you want an immutable object it means it cannot be changed after instantiation. This is good for things such as data from a DB that needs to remain set in stone for the duration of the cycle.
If you need to call the object and set or change data on it after instantiation, this is not an immutable object.
Would you take 2 wheels off a car and calling it a motorbike?
There is some talk about methods on an "immutable" class being named without the word "set", but this doesn't stop the functionality of them being a method that sets data. You could call it thisDoesNotSetAnything(int $id) and allow data to be passed in which changes the object. It'll be a setter, and thus the object is mutable.

Best practices for static constructors

I want to create an instance of a class and call a method on that instance, in a single line of code.
PHP won't allow calling a method on a regular constructor:
new Foo()->set_sth(); // Outputs an error.
So I'm using, if I can call it that, a static constructor:
Foo::construct()->set_sth();
Here's my question:
Is using static constructors like that considered a good practice and if yes, how would you recommend naming the methods for these static constructors?
I've been hesitating over the following options:
Foo::construct();
Foo::create();
Foo::factory()
Foo::Foo();
constructor::Foo();
Static constructors (or "named constructors") are only beneficial to prove an intention, as #koen says.
Since 5.4 though, someting called "dereferencing" appeared, which permits you to inline class instantiation directly with a method call.
(new MyClass($arg1))->doSomething(); // works with newer versions of php
So, static constructors are only useful if you have multiple ways to instantiate your objects.
If you have only one (always the same type of arguments and number of args), there is no need for static constructors.
But if you have multiple ways of instantiations, then static constructors are very useful, as it avoids to pollute your main constructor with useless argument checking, weakening languages constraints.
Example:
<?php
class Duration
{
private $start;
private $end;
// or public depending if you still want to allow direct instantiation
private function __construct($startTimeStamp = null, $endTimestamp = null)
{
$this->start = $startTimestamp;
$this->end = $endTimestamp;
}
public static function fromDateTime(\DateTime $start, \DateTime $end)
{
return new self($start->format('U'), $end->format('U'));
}
public static function oneDayStartingToday()
{
$day = new self;
$day->start = time();
$day->end = (new \DateTimeImmutable)->modify('+1 day')->format('U');
return $day;
}
}
As you can see in oneDayStartingToday, the static method can access private fields of the instance! Crazy isn't it ? :)
For a better explanation, see http://verraes.net/2014/06/named-constructors-in-php/
The naming of any method should be with intention revealing names. I can't tell what 'Foo::factory' does. Try to build to a higher level language:
User::with100StartingPoints();
This would be the same as:
$user = new User();
$user->setPointsTo(100);
You could also easily test whether User::with100StartingPoints() is equal to this.
If you don't need a reference to the newly constructed Foo, why don't you simply make set_sth a static function (and have it create a new Foo internally if required)?
If you do need to get hold of the reference, how would you do it? return $this in set_sth? But then set_sth can be made into a factory function anyway.
The only situation I can think of is if you want to call chainable methods (like in a fluent interface) on a newly constructed instance all in one expression. Is that what you are trying to do?
Anyway, you can use a general-purpose factory function for all types of objects, e.g.
function create_new($type) {
return new $type;
}
create_new('Foo')->set_sth();
It's probably not quite a best practice, but you could use the fact that functions and classes have two different namespaces : you can have a function that have the same name as a class.
This allows one to write this kind of code, for example :
function MyClass() {
return new MyClass();
}
class MyClass {
public function __construct() {
$this->a = "plop";
}
public function test() {
echo $this->a;
}
protected $a;
}
Note that I have defined a function called MyClass, and a class with the same name.
Then, you can write this :
MyClass()->test();
Which will work perfectly, and not get you any error -- here, you'll get the following output :
plop
Addition to Jon's answer: To allow constructor arguments use the following:
function create($type) {
$args = func_get_args();
$reflect = new ReflectionClass(array_shift($args));
return $reflect->newInstanceArgs($args);
}
create('Foo', 'some', 'args')->bar();
Documentation: ReflectionClass->newInstanceArgs
These are called creation methods, and I typically name them createXXX() such as createById() or createEmptyCatalog(). Not only do they provide a nice way to reveal the different intentions of an object's constructors, but they enable immediate method chaining in a fluent interface.
echo Html_Img::createStatic('/images/missing-image.jpg')
->setSize(60, 90)
->setTitle('No image for this article')
->setClass('article-thumbnail');
Propel uses a static method "create". I'd go with that. This method makes the code easier to test rather than just using static methods to perform business logic.
<?php
class MyClass
{
public static function create()
{
return new MyClass();
}
public function myMethod()
{
}
}
Besides, you can also pass parameters to the constructor. For instance:
<?php
class MyClass
{
public function __construct($param1, $param2)
{
//initialization using params
}
public static function create($param1, $param2)
{
return new MyClass($param1, $param2); // return new self($param1, $param2); alternative ;)
}
public function myMethod()
{
}
}
In either case, you'd be able to invoke myMethod right after the create method
<?php
MyClass::create()->myMethod();
// or
MyClass::create($param1, $param2)->myMethod();
A bit late to the party but I think this might help.
class MyClass
{
function __construct() {
// constructor initializations here
}
public static myMethod($set = null) {
// if myclass is not instantiated
if (is_null($set)) {
// return new instance
$d = new MyClass();
return $d->Up('s');
} else {
// myclass is instantiated
// my method code goes here
}
}
}
this can then be used as
$result = MyClass::myMethod();
optional parameters can be passed through either the __constructor or myMethod.
This is my first post and I hope I got the gimmicks right

Categories