Consider the following case:
class Factory {
private $x = 1;
private $y = 2;
private $z = 3;
public function create(string $instance) {
return new $instance($this->x, $this->y, $this->z);
}
}
class A {
private $x;
public function __construct ($x) {
$this->x = $x;
}
public function display() {
echo "<pre>$this->x</pre>";
}
}
class B {
private $x;
private $y;
private $z;
public function __construct ($x, $y, $z) {
$this->x = $x;
$this->y = $y;
$this->z = $z;
}
public function display() {
echo "<pre>$this->x</pre>";
echo "<pre>$this->y</pre>";
echo "<pre>$this->z</pre>";
}
}
$factory = new Factory;
$a = $factory->create("A");
$a->display();
$b = $factory->create("B");
$b->display();
As you can see, the factory will always provide 3 arguments when it creates a new instance. But in the class A, only 1 argument is needed by the constructor. Since php does not have the usual method overloading, so this does not cause an issue. But just to be safe, should I add an argument list parameter to the contructor of class A something like :
public function __construct ($x, ... $ignore) { ... }
to catch those unnecessary arguments as I know it will get those additional arguments every time. Or is the existing code sufficient?
If you pass in more variables, than required in a functions definition, those extra variables will be ignored (sample: https://3v4l.org/fNfAQ).
But this might be an indication, that you are trying to do too much with this particular factory and you might have better results by using a DI container.
Or you might need to have separate factories, for creating instances with different dependencies, instead of making a singe "make everything" factory.
Instead of passing separate parameters, you could use an associative array for all the constructors.
class A {
private $x;
public function __construct ($params) {
$this->x = $params['x'];
}
public function display() {
echo "<pre>$this->x</pre>";
}
}
class B {
private $x;
private $y;
private $z;
public function __construct ($params) {
$this->x = $params['x'];
$this->y = $params['y'];
$this->z = $params['z'];
}
public function display() {
echo "<pre>$this->x</pre>";
echo "<pre>$this->y</pre>";
echo "<pre>$this->z</pre>";
}
}
Then the factory can do:
public function create($instance) {
return new $instance(array('x' => $this->x, 'y' => $this->y, 'z' => $this->z));
}
Related
Lets say there is this class:
class Number {
private $asString;
private $asFloat;
public function __construct($input) {
$this->asString = $input;
$this->asFloat = $this->parse($input);
}
private function parse($input) {…}
//magic method for $n1 . $n2 operations
public function __toString() { … }
//method for $n1 + $n2 operations
public function __toFloat() { … }
}
Unfortunately the __toFloat() magic method does not exist. Is there any way, other than: $sum = $n1->toFloat() + $n2->toFloat(), without having to call that ->toFloat() method all the time, when the object is used in the context of mathematical operations.
In Javascript on has the ability to create a valueOf() method and I am searching for a way to create something similar in php. Any ideas?
You can use invoke as solution for this case
<?php
class Number
{
private $asString;
private $asFloat;
public function __construct($input)
{
$this->asString = $input;
$this->asFloat = $this->parse($input);
}
public function __invoke()
{
return $this->asFloat;
}
private function parse($input)
{
return (float) $input;
}
public function __toString()
{
return $this->asString;
}
}
$n1 = new Number(5);
$n2 = new Number(3);
var_dump($n1() + $n2());
so a class:
class ToBeUsed
{
private $a;
public function setSomething($a)
{
$this->a = $a;
}
public function getSomething()
{
return $this->a;
}
}
its beign created and updated:
$obj = new ToBeUsed();
$obj->setSomething('a');
and passed to another object
class UseIt
{
/**
* #var ToBeUsed
*/
private $obj;
public function __construct(ToBeUsed $obj)
{
$this->obj = $obj;
}
public function work()
{
$this->obj->getSomething();
$this->obj->setSomething(); //// !!!!! THIS IS BAD!
}
}
now a classic DI example, except that the passed object should be "dulled" - only some methods are allowed to use. E.g. getSomething() is allowed to use, but setSomething() is not. What pattern / practice can get away with it? There used to be friend classes is C but its Php...
class ToBeUsed
{
private $a;
public function setSomething($a)
{
$dbg = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,2);
if(count($dbg) > 1){
return;
}
$this->a = $a;
}
public function getSomething()
{
return $this->a;
}
}
class UseIt
{
/**
* #var ToBeUsed
*/
private $obj;
public function __construct(ToBeUsed $obj)
{
$this->obj = $obj;
}
public function work()
{
echo $this->obj->getSomething().PHP_EOL; // a
$this->obj->setSomething('b'); // this does nothing
echo $this->obj->getSomething().PHP_EOL; // a
}
}
$obj = new ToBeUsed();
$obj->setSomething('a');
$obj2 = new UseIt($obj);
$obj2->work();
Alternatively, you can perform more complex checks on debug_backtrace() output.
I would probably do something with Interfaces, it doesn't prevent a method form being used. But "they" (whoever they is) would be using it outside of the Interface for $obj.
Like this:
class ToBeUsed implements ToBeUsedInterface
{
private $a;
public function getSomething()
{
return $this->a;
}
public function setSomething($a)
{
$this->a = $a;
}
}
interface ToBeUsedInterface{
public function getSomething();
}
class UseIt
{
/**
* #var ToBeUsed
*/
private $obj;
public function __construct(ToBeUsedInterface $obj)
{
$this->obj = $obj;
}
public function work()
{
$this->obj->getSomething();
$this->obj->setSomething(); //This now exists outside of the interface for $obj
}
}
In terms of IDE's this would prevent the methods from auto-completing as well.
The only other thing I can think of, ( besides the other answer ) would be to set the method to protected and then use ReflectionMethod to change the viability, when you want to use it.
Another Option, is Using Reflection
class ToBeUsed
{
private $a;
public function getSomething()
{
return $this->a;
}
protected function setSomething($a)
{
$this->a = $a;
}
}
$ToBeUsed = new ToBeUsed();
$ReflectionMethod = new ReflectionMethod($ToBeUsed, 'setSomething');
$ReflectionMethod->setAccessible(true);
$ReflectionMethod->invoke($ToBeUsed, 'foo');
echo $ToBeUsed->getSomething();
Outputs:
foo
You can see it live here
And Obviously sense it's protected under normal conditions, it could not be used inside UseIt. If I was going to use this for any amount of code, I would extend or wrap the Reflection class. Just to make the call a bit more concise, like this:
class MyReflector
{
public static function invoke($class, $method, ...$args)
{
$ReflectionMethod = new ReflectionMethod($class, $method);
$ReflectionMethod->setAccessible(true);
$ReflectionMethod->invokeArgs($class, $args);
}
}
$ToBeUsed = new ToBeUsed();
MyReflector::invoke($ToBeUsed,'setSomething', 'foo');
Please note I got all fancy with the variadic ...$arg which is for PHP 5.6+ it just lets you do
MyReflector::invoke($ToBeUsed,'setSomething', 'foo', 'bar');
And $args would be ['foo','bar'] in the first example it's just ['foo'] which can be used for invokeArgs for the second argument which takes an array of arguments to pass on to the actual method.
class Point
{
private $x, $y;
public __construction ($x, $y)
{
$this->x = $x;
$this->y = $y;
}
public function getX()
{
return $this->x;
}
public function getY()
{
return $this->y;
}
}
first I would write this:
class Item
{
private $point; // Point
public __construction()
{
$this->point = new Point(0,0);
}
public function getPoint()
{
return $this->point;
}
}
and then:
$p = new Item();
$p->getPoint()->getX();
but they say it violates that law. After refactoring:
class Item
{
private $point; // Point
public __construction()
{
$this->point = new Point(0,0);
}
public function getPointX()
{
return $this->point->getX();
}
public function getPointY()
{
return $this->point->getY();
}
}
and then:
$p = new Item();
$p->getPointX();
this time getPointX() and getPointY() is just a redundant "transmission" method. I understand that ig Point has 1000 other methods, it would be unsafe to just return this all object as return $this->point. But this time all properties are covered.
Source
Because your $p requires more information about Point than it needs:
In particular, an object should avoid invoking methods of a member object returned by another method
I gave myself an exercise to understand the Command design pattern. I created interfaces for Placeable, Placer, and Placement where the idea was Placer would use the Placement command to change Placeable. I used simple x,y values for the place values. X and y in Placeable are private. (Shouldn't they be? Otherwise anything could change the location.) As you can see in the code below, my 'invoker' ended up inside the 'receiver.' This doesn't look like the examples I found online. Like this https://en.wikipedia.org/wiki/Command_pattern#Java. But, those examples use public properties. Have I done something really wrong in my exercise? As an aside, aren't examples which use public properties bad in terms of encapsulation? What is the point of Command designs if anything could access public properties or methods?
<?php
// receiver
interface Placeable
{
public function locate();
public function toPlace(Placement $placement);
}
// client
interface Placer
{
public function place(Placeable $placeable, $x=0, $y=0);
}
// command
interface Placement
{
public function setX($x=0);
public function setY($y=0);
public function getX();
public function getY();
}
///////////////////////////////////////////////////////////////////////
// receiver
class Book implements Placeable
{
private $x = 0;
private $y = 0;
public function locate()
{
return '(' . $this->x . ',' . $this->y . ')';
}
// invoker is inside the receiver, because the command changes private properties
public function toPlace(Placement $placement)
{
$this->x = $placement->getX();
$this->y = $placement->getY();
}
}
// command
class PlacementCommand implements Placement
{
private $x = 0;
private $y = 0;
public function setX($x=0)
{
$this->x = $x;
}
public function setY($y=0)
{
$this->y = $y;
}
public function getX()
{
return $this->x;
}
public function getY()
{
return $this->y;
}
}
// client
class Person implements Placer
{
public function place(Placeable $placeable, $x=0, $y=0)
{
$placement_command = new PlacementCommand();
$placement_command->setX($x);
$placement_command->setY($y);
$placeable->toPlace($placement_command);
}
}
?>
<pre>
<?php
$book = new Book();
$person = new Person();
$person->place($book, 3, 4);
//
echo var_dump($book);
?>
</pre>
For example consider class X that has some utility methods ('foo','bar') that do some operation on some property of X. These method are also useful for other external variable.
Some may implement X and staticX classes as below:class Foo
class StaticX
{
public static function foo($p)
{
return $p * $p;
}
}
class X
{
private $p=4;
public function foo()
{
return StaticX::foo($this->p);
}
}
$x= new x;
echo $x->foo();
echo StaticX::foo(3);
But this approach has some maintainability issues.
Is there any better solution?
class X
{
private $p;
public function foo()
{
return self::doFoo($this->p);
}
public static function doFoo($p)
{
return $p * $p;
}
}
I like foolishSeths answer, but what about this?
class X
{
private static $p;
public static function foo($p=null)
{
if ( is_null( $p ) ) {
$p = self::$p;
}
return $p * $p;
}
}
Since PHP 5.4 you can make use of traits. See http://www.php.net/manual/en/language.oop5.traits.php
trait fooBehavior {
function getFoo() { return self::foo($this->p); }
static function foo($p) { return $p * $p; }
}
class X {
use fooBehavior;
private $p;
public function __construct($p) { $this->p = $p; }
}
$x = new X(2);
echo $x->getFoo(); // echoes 4
echo $x::foo(2); // echoes 4