PHP Have Object Return Different Object - php

In a few different places I call:
$model=NEW MakeCall($form);
I have updated the MakeCall class with several changes that I want to take affect after a given date. I renamed the original class MakeCallOld
How can I leave my calls to:
$model=NEW MakeCall($form);
intact and within MakeCall do this:
class MakeCall
{ ...
public function __construct($form)
{
//Use Legacy MakeCallOld for stuff before 2016-10-01
if ($form['date']<'2016-10-01') {
$object=NEW MakeCallOld($form);
return $object;
}
$this->perform several functions and set variables...
This currently just returns an empty object of class MakeCallOld but it does not appear to run the constructor in MakeCallOld as all properties are empty. I would just like the entire object of MakeCallOld dropped into $model.

What you need is a static factory constructor. This is the way you should be doing it to add initialization logic or switch constructors depending on the argument.
class MakeCall
{
public function __construct($form)
{
$this->form = $form;
}
public function showForm(){
echo $this->form;
}
public static function create($form){
//put logic for picking object or whatever here!
$object = new MakeCall($form);
//Do more initializing if you want here!
return $object;
}
}
$form = "asdasd";
$model= MakeCall::create($form);
$model->showForm();

Constructors don't have a return value, so by saying return $object you are simply ending the control flow there and doing nothing else, never reaching "perform several functions and set variables". Depending on your structure you should consider making MakeCall inherit from MakeCallOld, then you can simply call parent::__construct(); in MakeCall's constructor.

Related

Array in an object passed by reference is empty, even though it was filled later on

In the progress of writing a little framework for a web app I came along some difficulties in making classes communicate with each other.
Environment
I have an abstract class called LizardModule, that should be extended by all the single modules of the web-app. This class has a final protected function registerController(...), that creates a new Object of the type LizardController. This is, as it sounds, based on the idea of MVC. With the final protected function registerFunction(...), modules can register functions for every controller. Those are stored using addFunction(...) on the controller object. Here is what this looks like:
Example Module:
class ModuleOverview extends LizardModule {
protected function setup() {
$this->registerController(
'overview',
'App Overview'
);
$this->registerFunction(
'overview',
'myfunction',
'My Function',
array(&$this, 'theFunctionToCall')
);
}
public function theFunctionToCall() { ... Generate Content ... }
}
Module Class:
class LizardModule {
private $controllers = array();
final public function __construct() { $this->setup(); }
abstract protected function setup();
[...]
final protected function registerController($controllerSlug, $controllerName) {
if (array_key_exists($controllerSlug, $this->controllers))
return false;
$this->controllers[$controllerSlug] = new LizardController($controllerSlug, $controllerName);
}
final protected function registerFunction($controllerSlug, $functionSlug, $functionName, callable $function) {
if (!array_key_exists($controllerSlug, $this->controllers))
return false;
$this->controllers[$controllerSlug]->addFunction($functionSlug, $functionName, $function);
}
}
This results in a lot of objects of type LizardController in different places of the app. To make all of those objects accessable, I created a singleton class LizardRouter, that should hold a reference to all of those controller objects. Therefore, the controller-object registers itself with this singleton class:
Controller Class:
class LizardController {
[...]
private $functions = array();
public function __construct($slug, $name, $menu) {
$this->slug = $slug;
$this->name = $name;
$this->menu = $menu;
LizardRouter::registerController($this);
}
public function addFunction(...) { Tested, this works. }
public function getFunctions() {
return $this->functions;
}
}
Router Class:
final class LizardRouter {
[...]
public static function getControllers() {
return static::getInstance()->controllers;
}
public static function registerController(LizardController $controller) {
static::getInstance()->controllers[] = $controller;
}
}
The Problem
The whole thing works alright for the controllers. In my interface class, I can read out all controllers and print a menu containing their names. The problem is: Whenever I access the controllers functions-array (see controller class) through the controllers-array given by the routing class, I get an empty array. I asume that somewhere a reference is not working and I am passing the actual controller object, before my module-class was able to add the functions to the controllers functions-array. But I can't figure out where exactly the problem lies. Here is an example from my interface class showing the problem:
foreach (LizardRouter::getControllers() as $controller) {
// Allways returns an empty array, even though
// the module added functions to the controller.
$controller->getFunctions();
}
Since this is a very specific case, I guess it is unlikely, that anyone will ever stumble upon the same problem. Anyway; I found the reason for the problem:
Objects are by default passed as reference since PHP5. Variables are by default passed by value.
Arrays are handled like variables, so when I pass an array containing object-references, a new copy of this array is created and passed. Object references added to the array after it was passed are therefore only added to the original array.
The solution i chose was to create my own "array-class" for holding objects. It has nothing more than a private array object, a setter and a getter. Since this custom array class is an object, it is automatically passed by reference. Later I also added some functions to conveniently access the array - a good side-effect.

Call a method after __construct in finished

Basically I have a method which I need to run when the constructor is finished (the method is called persist() and it simply saves a key which was generated during the constructor into the session). It seems simple enough, and it works - at the end of __construct I make the call to $this->persist().
The problem is that this class is subclassed many times. This causes two issues.
One, that I must remember to make the call to persist() at the end of every single subclass's __construct method. Not a huge issue but it doesn't feel very OOP, I feel like I could be dealing with this in the parent class some how and that this would be better.
Two, if a subclass is subclassed (which it is), and the __construct methods chained (i.e. parent::__construct called), the persist() method will be getting fired multiple times, once for each time the class has been subclassed. It only needs to be called once, when all construction is complete. In this scenario it doesn't really break anything because when the persist method is called for the 2nd, 3rd time etc., it simply overwrites what was persisted before. But that isn't the point, because I just feel like there must be a better way and that there are scenarios out there that would not allow for the method to be called multiple times.
Is a factory method which constructs the object and then makes the call to persist on it the only way? I can go down this route but I am just wondering if there is a way to do it without, so that the method from the parent is always called after construction.
Here is some example code:
session_start();
is(!isset($_SESSION["Component"])) $_SESSION["Component"] = [];
abstract Class Component
{
private $id;
protected $key;
function __construct($id = NULL)
{
$this->id = $id;
$this->key = [];
$this->key["something"] = "SomeValue";
$this->persist(); // First call
}
protected function persist()
{
if($this->id !== NULL) $_SESSION["Component"][$this->id] = $this->key;
}
}
Class SomeComponent extends Component
{
function __construct($id = NULL)
{
parent::__construct($id);
$this->key["something-else"] = "SomeOtherValue";
$this->persist(); // Second call
}
}
Class SomeSpecialistComponent extends SomeComponent
{
function __construct($id = NULL, $key = [])
{
parent::__construct($id);
$this->key = array_merge($this->key, $key);
$this->persist(); // Third call
}
}
$my_component = new SomeSpecialistComponent(1, ["example" => true]);
Only trick I found to get something similar (except I wanted to execute things before and not after) is using a parent class with an abstract method as a new constructor :
abstract class RequireThings {
public function __construct() {
$this->constructAndPersist();
$this->persist();
}
abstract function constructAndPersist();
// You could also set this function in your children classes by the way.
public function persist() {
echo ' Then I persist!';
}
}
class UsingPersist extends RequireThings {
public function constructAndPersist() {
echo 'I do my things first.';
}
}
$class = new UsingPersist();
Would output :
I do my things first. Then I persist!
If I got your problem right, it should be enough to avoid problems you are facing.
The main downside of this solution is that you have to use a new function which is supposed to be your new constructor for this type of classes. That's why I set the __constructPersist as abstract, it forces the behavior as wanted.
I would argue in favor of the factory method, mostly because you're doing real work in the constructor. Remove the call where work is being done in the constructors ($this->persist) and place it in the factory:
class ComponentFactory
{
const SOME_COMPONENT = 'component';
const SOME_SPECIALIST_COMPONENT = 'specialist_component';
public static function make($type, $id, $key = null)
{
switch($type) {
case self::SOME_COMPONENT:
$component = new SomeComponent($id);
break;
case self::SOME_SPECIALIST_COMPONENT:
$component = new SomeSpecialistComponent($id, $key);
break;
}
$component->persist();
return $component;
}
}
$component = ComponentFactory::make(ComponentFactory::SOME_COMPONENT, 42);
$specialist = ComponentFactory::make(
ComponentFactory::SOME_SPECIALIST_COMPONENT,
43,
[
'something' => 'SomeValue',
'something-else' => 'SomeOtherValue',
]
);
According to Miško Hevery (author of AngularJS and agile coach at Google) these are the warning signs of doing too much work in the constructor:
new keyword in a constructor or at field declaration
Static method calls in a constructor or at field declaration
Anything more than field assignment in constructors
Object not fully initialized after the constructor finishes (watch
out for initialize methods)
Control flow (conditional or looping logic) in a constructor
CL does complex object graph construction inside a constructor
rather than using a factory or builder
Adding or using an initialization block
just create another function that you'll call before $this->persist and override that in your subclasses instead of the constructor

Call base Class function

say I have :
File BaseFoo.php :
require('MyClass1.php')
class BaseFoo(){
function check(){
//do somme stuff
}
function f1($o){
$c = new MyClass1();
return $c->f1($o);
}
}
File MyClass1.php :
MyClass1(){
function f1(){
???->check() // how to call check() (in initiator BaseFoo class) ?
// do other stuff
}
}
Now question is : in MyClass1, function f1, I want to call check() function which is in initiator Class.
Thank for help !
Because BaseFoo doesn't extend MyClass1, it isn't called a base class. This means that you indeed can't use parent. You need to have an object on which you can call the method.
Depending on what you want, you may need to create an object (or pass one) of class BaseFoo in MyClass1 (local or as a member) or you may make BaseFoo::check() static:
class BaseFoo(){
static function check(){
// Note: you can only access static members here
// Calling non-static methods statically generates an E_STRICT level warning.
}
function f1($o){
$c = new MyClass1();
return $c->f1($o);
}
}
Most likely, however, that's not what you actually want to do. You should ask the question "Who owns what?". Here, BaseFoo owns the MyClass1 object. So you probably want this:
class BaseFoo(){
function check(){
//do somme stuff
}
function f1($o){
$c = new MyClass1();
check();
return $c->f1($o);
}
}
And:
MyClass1(){
function f1(){
// Don't check here, the creator should check
// do other stuff
}
}
You may need to check for different things both in MyClass1 and in BaseFoo though, and you would have 2 separate check methods for that.
you can make function check 'static' so u can call BaseFoo::check()
If you google it you will find your answer, but Check this page
So you can use something like that:
class BaseFoo(){
public static function check(){
//do somme stuff
}
function f1($o){
$c = new MyClass1();
return $c->f1($o);
}
}
class MyClass1(){
function f1(){
BaseFoo::check() // call static function check from BaseFoo
// do other stuff
}
}

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

PHP: 'Dynamic' callback from inside/outside a class

we have a problem [cit.]
I need to assign a callback dynamically within a class, in base of a variable param: my goal is to have just one class (and not a main class and many extender sub-class), and inside this class if a value is X, then the funcitonX must be used, if is Y, the functionY.
I know i cant explain well, i hope my example will do:
class plzComplicateMyLife{
public $vehicle;
public $kindVehicle;
public $dynamicFunction;
public function __construct($vehicle, $kindVehicle){
$this->kindVehicle = $kindVehicle;
$this->vehicle = $vehicle;
switch($kindVehicle){
case 'cycle':
$this->dynamicFunction = "isACycle";
break;
case 'car':
$this->dynamicFunction = "isACar";
break;
}
//here come the problem, i need to call the callback store in dynamicFunction.
//i tried:
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//error: Catchable fatal error: Object of class plzComplicateMyLife could not be converted to string in [...]
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//Warning: call_user_func(plzComplicateMyLife::isACar) [function.call-user-func]: First argument is expected to be a valid callback in [...]
//$this->dynamicFunction();
//Fatal error: Call to undefined method plzComplicateMyLife::dynamicFunction() in [...]
//so, how can i do that?
}
public function isACycle($vehicle){
echo 'im a cycle, model: '.$vehicle.'<br />';
}
public function isACar($vehicle){
echo 'im a car, model: '.$vehicle.'<br />';
}
//i know this has no sense, in this example at least.
public function printKind(){
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//then?
}
}
$maserati = new plzComplicateMyLife('maserati4', 'car');
//then, maybe, outside the class i'll need to recover the callback:
$maserati->printKind();
EDIT:
As Rob said, polymorphism would be really a good solution.
But the problem is that, in this case, i really must have the same declaration for every class instance, changing only the parameters...e.g:
$maserati = new plzComplicateMyLife('maserati4', 'car');
$ducati = new plzComplicateMyLife('maserati4', 'cycle');
//is good
//becose i cant have:
$maserati = new plzComplicateMyLifeWithACar('maserati4');
$ducati = new plzComplicateMyLifeWithACycle('maserati4');
Polymorphism is the way to go here but for future reference you can also do this:
public function printKind() {
$this->{$this->dynamicFunction}($this->vehicle);
}
In response to your edit, could you not do something like this instead?
abstract class MethodOfTransport {
protected $model;
public function __construct($model) {
$this->model = $model;
}
abstract public function printKind();
public static function create($model, $type) {
$object = new $type($model);
return $object;
}
}
class cycle extends MethodOfTransport {
public function printKind() {
echo 'im a cycle, model: '.$this->model.'<br />';
}
}
class car extends MethodOfTransport {
public function printKind() {
echo 'im a car, model: '.$this->model.'<br />';
}
}
$maserati = MethodOfTransport::create('maserati4', 'car');
$maserati->printKind();
$ducati = MethodOfTransport::create('maserati4', 'cycle');
$ducati->printKind();
In PHP you can use specify a method callback using an array as a callback variable (see here), for example:
array( $object, $methodName );
So you could do this
$callback = array($this, $this->dynamicFunction);
call_user_func($callback, $this->vehicle);
Er, why don't you want to use a simple inheritance structure here? If you want different behaviour depending upon the object modelled, then that's pretty much the canonical description of polymorphism.
If you really do want to plough on with callbacks into the same object, then you'll need to do one of two things:
Drop the $vehicle parameter from your callbacks, make them private or protected, and call into them normally, i.e.
call_user_func( array( $this, 'isACycle' ) );
Mark the callback as static, make them private or protected, and call into them as follows:
call_user_func( array( __CLASS__, 'isACycle' ), $this );
Within the non-static callback, access the object's properties via $this in the normal fashion. Note also that I suggest marking the callback as private or protected, in order to prevent unnecessary outside callers; presumably, you don't want them executing the wrong method for each type.

Categories