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());
Related
Consider class with non-deterministic method:
class Foo
{
public function getSome(): int
{
static $int = 0;
return ++$int;
}
}
How can I mock same behaviour using Mockery?
class Bar
{
public function useFoo(Foo $foo)
{
echo $foo->getSome() . ", ";
echo $foo->getSome() . ", ";
echo $foo->getSome();
}
}
$mock = Mockery::mock(Foo::class);
$mock->shouldReceive('getSome')->andReturn(1);
$mock->shouldReceive('getSome')->andReturn(2);
$mock->shouldReceive('getSome')->andReturn(3);
// Should display 1, 2, 3
$bar = new Bar();
$bar->useFoo($mock);
Another example:
class Clock
{
public function getTime(): int
{
return time();
}
}
class Sleeper
{
public function sleep(int $seconds): void
{
sleep($seconds);
}
}
How can I mock same behaviour using Mockery?
class Stoper
{
private Clock $clock;
private Sleeper $sleeper;
public function __construct(Clock $clock, Sleeper $sleeper)
{
$this->clock = $clock;
$this->sleeper = $sleeper;
}
public function measure(int $seconds): int
{
$start = $this->clock->getTime();
$this->sleeper->sleep($seconds);
return $this->clock->getTime();
}
}
$clockMock = Mockery::mock(Clock::class);
$clockMock->shouldReceive('getTime')->andReturn(1000000001);
$clockMock->shouldReceive('getTime')->andReturn(1000000011);
$sleeperMock = Mockery::mock(Sleeper::class);
$sleeperMock->shouldReceive('sleep');
$stoper = new Stoper($clockMock, $sleeperMock);
$this->assertEquals(10, $stoper->measure(10));
Dirty solution
I figured out I can make dirty trick
class ClockCaller
{
public function getTime(int $callNumber)
{
return (new Clock())->getTime();
}
}
class Stoper
{
private ClockCaller $clockCaller;
private Sleeper $sleeper;
public function __construct(ClockCaller $clockCaller, Sleeper $sleeper)
{
$this->clockCaller = $clockCaller;
$this->sleeper = $sleeper;
}
public function measure(int $seconds): int
{
$start = $this->clockCaller->getTime(1);
$this->sleeper->sleep($seconds);
return $this->clockCaller->getTime(2);
}
}
$clockMock = Mockery::mock(ClockCaller::class);
$clockMock->shouldReceive('getTime')->withArgs([1])->andReturn(1000000001);
$clockMock->shouldReceive('getTime')->withArgs([2])->andReturn(1000000011);
But it seems very nasty
The answer to your question is given by the Simple Example in the Mockery documentation. A temperature service that should return successively 10, 12 and 14 degrees can be mocked like this:
$service = Mockery::mock('service');
$service->shouldReceive('readTemp')
->times(3)
->andReturn(10, 12, 14);
So, for your Foo class:
$mock = Mockery::mock(Foo::class);
$mock->shouldReceive('getSome')
->times(3)
->andReturn(1, 2, 3);
and for your Clock:
$clockMock = Mockery::mock(Clock::class);
$clockMock->shouldReceive('getTime')
->times(2)
->andReturn(1000000001, 1000000011);
you can check the output with expectOutputString:
public function testFoo(){
$this->expectOutputString("foo");
echo "foo";
}
about sleep function, you can use \sleep() (global namespase), and override it..
also, you can use mocking built-in PHP functions
How can'i create a classe calculator witch can do ita differents operations like : addition , multiplication but with this format $test->two()->add()->one() ==> the result is 3.
Can you help me ?
thank you
class Test
{
private $result;
function __construct()
{
$this->result = 0;
}
function one()
{
$this->result = 1;
return $this;
}
function two()
{
$this->result = 2;
return $this;
}
function add()
{
$this->result += $this->result;
return $this;
}
function getResult()
{
return $this->result;
}
}
$test = new Test();
$a = $test->One()->add()->two();
var_dump($a->getResult());
I did this programm but i didn't had the correct response
the result returned is 2 but i must have 3 (1+2)
Here is a solution.
It works on the basis that add() or subtract() doesn't directly carry out any work, it simply sets a "pending" operation, and that one() or two() (I've shortcut that style to key($num) for simplicity though, I think it's better and more flexible as well) actually does the the last operation specified by add() or subtract(), using the number specified in the input.
It works by using PHP's ability to specify a function to call using a string value. Bit hacky but it seems to work.
class Calculator
{
private $result;
private $nextOp;
function __construct()
{
$this->result = 0;
$this->nextOp = "addVal";
}
function key($num)
{
$this->{$this->nextOp}($num);
return $this;
}
function add()
{
$this->nextOp = "addVal";
return $this;
}
function subtract()
{
$this->nextOp = "subtractVal";
return $this;
}
private function addVal($num)
{
$this->result += $num;
}
private function subtractVal($num)
{
$this->result -= $num;
}
function result()
{
return $this->result;
}
}
$test = new Calculator();
$a = $test->key(1)->add()->key(2)->key(3)->subtract()->key(2)->result();
var_dump($a);
This outputs 4.
N.B. It assumes that if you wrote e.g. key(1)->add()->key(2)->key(2) the second call to key(2) would also do an add, because that was the last operation specified (so the result would be 5 in that case), and also the initial operation is always add as well (although I guess you could allow that to be specified in the constructor). I don't know if these assumptions are acceptable in your scenario, you didn't specify what should happen if the user write something like this, or what the class should do with the initial value.
Live demo: http://sandbox.onlinephpfunctions.com/code/0be629f803261c35017ae49a51fa24385978568d
this is my response. It's worked very fine
// Interface des opérations
interface Operation {
public function plus();
public function minus();
public function divededInto();
public function times();
public function doOperation($value);
}
// Class Calculator
class Calculator implements Operation {
private $result;
private $operation;
private $numbers;
public function __construct($numbers) {
$this->numbers = $numbers;
$this->result = 0;
$this->operation = null;
}
//Surcharge de la méthode __call
public function __call($name, $arguments){
$name = strtolower($name);
$this->doOPeration($this->numbers[$name]);
$this->operation = null;
return $this;
}
// Exécution de l’opération
public function doOperation($value){
switch ($this->operation ){
case '+':
$this->result += $value;
break;
case '-':
$this->result -= $value;
break;
case '/':
$this->result = intDiv($this->result,$value);
break;
case '*':
$this->result *= $value;
break;
default : $this->result = $value;
}
}
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));
}
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
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