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;
}
}
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());
I am having the following class:
class StuffDoer{
public function __construct(Dep1 $dep, Dep2 $dep2, array $array){
$this->dep = $dep;
$this->dep2 = $dep2;
$this->array = $array;
}
public function genericDoStuff($param){
// Do stuff here...
}
public function doStuffForMark(){
return $this->genericDoStuff('Mark');
}
public function doStuffForTim(){
return $this->genericDoStuff('Tim');
}
public function doStuffForAlice(){
return $this->genericDoStuff('Alice');
}
}
After some months, I am asked to make the method genericDoStuff($param), along with all the methods that depend on it, use an extra parameter in a single part of the application. Instead of changing the signature on every single method that depends on genericDoStuff, I ended up with the following:
class StuffDoer{
public function __construct(Dep1 $dep, Dep2 $dep2, array $array){
$this->dep = $dep;
$this->dep2 = $dep2;
$this->array = $array;
}
public function forParameter($param){
$self = clone $this;
$this->param = $param;
return $self;
}
public function genericDoStuff($param){
if($this->param !== null){
// Do stuff by taking param into account
} else {
// Do stuff stuffdoer does
}
}
public function doStuffForMark(){
return $this->genericDoStuff('Mark');
}
public function doStuffForTim(){
return $this->genericDoStuff('Tim');
}
public function doStuffForAlice(){
return $this->genericDoStuff('Alice');
}
}
That way, I am able to do this in the single point of the application:
$myStuffDoer = $serviceContainer->get('stuff_doer');
$myStuffDoer->forParameter('AAAARGHITBURNSGODHELPME')->doStuffForMark();
// Future usages of $myStuffDoer are unaffected by this!
So my question is this: Is this considered a bad practice for any reason?
I'm trying to build a function inside a PHP class, however whenever I invoke the function, I am only returning the first variable.
class Nums
{
private $a = 7;
private $b = 8;
public function sum()
{
return $this->a + $this->b;
}
public function __set($name,$value) {
switch($name) {
case 'a':
return $this->setA($value);
case 'b':
return $this->setB($value);
}
}
public function __get($name) {
switch($name) {
case 'a':
return $this->getA();
case 'b':
return $this->getB();
}
}
private function setA($i) {
$this->a = $i;
}
private function getA() {
return $this->$a;
}
private function setB($i) {
$this->b = $i;
}
private function getB() {
return $this->$b;
}
}
Am I doing something wrong here, because I can't really see what is wrong with this logic.
It's working for me. Here's what i tried and it output 15.
PHP CODE :
<?php
class Nums
{
private $a = 7;
private $b = 8;
public function sum()
{
return $this->a + $this->b;
}
}
$obj = new Nums();
$c = $obj->sum();
echo $c;
?>
OUTPUT :
15
class Nums
{
private $a = 7;
private $b = 8;
public function sum()
{
return $this->a + $this->b;
}
}
$numObj = new Nums();
echo $numObj->sum();
Running this code returns 15 for me
Maybe I'm wrong to expressed it in the title, but I just do not understand how in the class like this.
<?php
class sample{
public $data = [];
public function pushIndex($index){
array_push($this->data, $index);
}
public function pushValue($value){
array_push($this->data["index"], $value);
// Some magic
}
public function forIndex($index){
return $this->data[$index];
// Some magic
}
}
To realize scheme like in Symfony, where will be spaghetti like this
<?php
$a = new sample;
$a->pushIndex("index")->pushValue("value");
$a->forIndex("index2")->pushValue("value2");
Maybe someone knows how to do it?
What you're talking about is called Fluent interface.
Returns the current object by using $this.
public function pushIndex($index){
array_push($this->a,$index);
return $this;
}
But what you want is to do something like this:
class sample
{
protected $a = [];
protected $currentIndex = null;
public function pushIndex($index)
{
$this->currentIndex = $index;
return $this;
}
public function pushValue($value)
{
if ($this->currentIndex === null) {
throw new LogicException('You need to call "pushIndex" or "forIndex" first.');
}
$this->a[$this->currentIndex] = $value;
return $this;
}
public function forIndex($index)
{
if (!isset($this->a[$index])) {
throw new RuntimeException(sprintf('Index "%s" doesn\'t exists', $index));
}
$this->currentIndex = $index;
return $this;
}
public function getArray()
{
return $this->a;
}
}
$a = new sample;
$a->pushIndex("index")->pushValue("value");
$a->forIndex("index2")->pushValue("value2"); // exception?
var_dump($a->getArray());
But what you want is pretty unclear.
I think what you're trying to achieve is something like this:
class sample{
public $a = [];
public $index = null;
public function pushIndex($index){
$this->index = $index;
$this->a[$index] = null;
return $this;
}
public function pushValue($value){
$this->a[$this->index] = $value;
return $this;
}
public function forIndex($index){
$this->index = $index;
return $this;
}
}
$a = new sample;
$a->pushIndex("index")->pushValue("value");
$a->forIndex("index2")->pushValue("value2");
echo "<pre>";
var_dump($a);
echo "</pre>";
This is called "method chaining". By returning a reference to the called object, you're able to perform further methods on the object, essentially "chaining" the methods.
I've had to adjust your code a little to get it the work I believe the way you want it to. It should provide a working example to help you understand method chaining.
I have been reading Rafactoring by Martin Fowler and in the beginning of the book he uses an example application (written in Java), which I am trying to convert over to PHP for training purposes. (I have trimmed the code down to make this question, but it works if the variables are public.)
The trouble is to create a statement I need access to a value (see switch) using method getCode() of Movie class since $code is private. (Of course if all of the variables were public the code below would work, but I want to keep them private.)
Can someone please shed some light on how I would access the private variable calling the getCode() method of Movie from the switch in statement(). (Or if there is a better way to do it, let me know.)
class Movie {
private $title;
private $code;
public function __construct($title, $code) {
$this->title = $title;
$this->code = $code;
}
public function getCode() {
return $this->code;
}
public function getTitle() {
return $this->title;
}
}
class Rental {
private $movie; // will carry a Movie object
private $days;
public function __construct(Movie $movie, $days) {
$this->movie = $movie;
$this->days = $days;
}
public function getMovie() {
return $this->movie;
}
}
class Customer {
private $name;
private $rentals; // will be a collection of Rental Objects
public function __construct($name) {
$this->name = $name;
}
public function addRental(Rental $rental) {
$this->rentals[] = $rental;
}
public function statement() {
$thisAmount = 0;
foreach ($this->rentals as $each) {
// what is the better way to call this value??????
switch ($each->movie->code) {
case 1:
$thisAmount+= ($each->days - 2) * 1.5;
break;
case 2:
$thisAmount += $each->days * 3;
break;
case 3:
$thisAmount += 1.5;
break;
}
// show figures for this rental
$result = "\t" . $each->movie->title . "\t" . $thisAmount . "\n";
}
return $result;
}
}
// pick a movie
$movie = new Movie('Star Wars', 0);
// now rent it
$rental = new Rental($movie, '2');
// now get statement
$customer = new Customer('Joe');
$customer->addRental($rental);
echo $customer->statement();
You are iterating over a collection of movie in your foreach. So you can do it this way:
foreach($this->rentals as $rental) {
switch($rental->getMovie()->getCode()) {
Of course, you can leave your variable named each. I just find $movie more readable and understandable in this context.
replace your line with just:
$each->getMovie->getCode()