How this class and sub methods use works? - php

I have been browsing some php source code and need to know how the following class and sub methods use works:
<?php
$me = new Person;
$me->name("Franky")->surname("Chanyau")->phone("+22", "456 789");
?>
I have pretty solid knowledge of OOP so I don't want a 101. I just need to know how to make the above code possible.

Method chaining is possible, by
return $this;
at the end of the method.
Explained here:
phpandstuff: Method Chaining Plus Magic Setters
These methods usually set an instance variable and then just return $this.
public function phone($param) {
$this->phone = $param;
return $this;
}

methods name() surname() and phone() return an instance of Person. you can accomplish this by
return $this;
most probably these methods look like this:
public function name($name) {
$this->name = $name;
return $this;
}

like some others said, its a fluid interface http://en.wikipedia.org/wiki/Fluent_interface#PHP the Basic Idea is that a methof of a class always returns the object itself
class Car {
private $speed;
private $color;
private $doors;
public function setSpeed($speed){
$this->speed = $speed;
return $this;
}
public function setColor($color) {
$this->color = $color;
return $this;
}
public function setDoors($doors) {
$this->doors = $doors;
return $this;
}
}
// Fluent interface
$myCar = new Car();
$myCar->setSpeed(100)->setColor('blue')->setDoors(5);
(via wiki)

It's called method chaining. Basically each class function returns the object itself ($this) so that the user can call more functions on the returned object.
public function name() {
//other stuff...
return $this;
}
http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html
http://www.electrictoolbox.com/php-method-chaining

The idea is if we return $this then we can chain the object method calls together. Here's the solution:
<?php
class Person
{
private $strName;
private $strSurname;
private $ArrPhone = array();
public function name($strName)
{
$this->strName = $strName;
return $this; // returns $this i.e Person
}
public function surname($strSurname)
{
$this->strSurname = $strSurname;
return $this; // returns $this i.e Person
}
public function phone()
{ $this->ArrPhone = func_get_args(); //get arguments as array
return $this; // returns $this i.e Person
}
public function __toString()
{
return $this->strName." ".$this->strSurname.", ".implode(" ",$this->ArrPhone);
}
}
$me = new Person;
echo $me->name("Franky")->surname("Chanyau")->phone("+22", "456 789");
?>

Correct answers, but to make the code work you should write:
$me = new Person();
instead of
$me = new Person;

Related

Some more syntactic sugar with the "with" statement?

I like PHP, but I miss some of the constructs from other languages that although don't do anything for performance, make the code look cleaner and possibly more maintainable. I'm thinking of Visual Basic days and the "with" statement.
So ideally in PHP we could do this:
with($myWellDescribedInstance) {
->property1="string";
->property2=1;
->property3=2;
->myMethod();
}
Instead of
$myWellDescribedInstance->property1="string";
$myWellDescribedInstance->property2=1;
$myWellDescribedInstance->property3=2;
$myWellDescribedInstance->myMethod();
Is there anything like this in PHP?
You can implement a fluent interface on any class just by having a function return $this.
This is mostly used for setters, but of course it works for any method for which you would normally not have a return value.
For example:
class Person
{
protected $name = '';
protected $surname = '';
protected $email = '';
public function getName()
{
return $this->name;
}
public function getSurname()
{
return $this->surname;
}
public function getEmail()
{
return $this->email;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function setSurname($surname)
{
$this->surname = $surname;
return $this;
}
public function setEmail($email)
{
$this->email = $email;
return $this;
}
}
Usage:
$person = new Person;
$person->setName('John')
->setSurname('Doe')
->setEmail('johndoe#email.com');
Of course, calling the method (for example) setName or withName would be entirely up to you.
Another idea might be to have both a setName method (which doesn't return anything) and a withName method (which returns $this), but that might be a bit of an overkill.
If you use "setters" instead of direct property access you can chain methods.
class A {
private $a;
private $b;
public function setA($a)
{
$this->a = $a;
return $this;
}
public function setB($b)
{
$this->b = $b;
return $this;
}
public function doSomething()
{}
}
$a = new A();
$a->setA('a')
->setB('b')
->doSomething();

How to load data with new self construction php

I can not load data to properties using this construction I receive null in dump
<?php
namespace App\Domain\Good;
class GoodDto
{
public $name;
public $articul;
public $price;
public $type;
public $qnt;
public $discount;
public $category;
public $description;
public $description2;
public $color;
public function load($data)
{
$this->name = $data['name'];
$this->articul = $data['artikul'];
$this->price = $data['price'];
$this->type = (isset($data['type'])) ? $data['type'] : null;
$this->qnt = $data['count'];
$this->discount = $data['spinner-decimal'];
$this->category = $data['id_cat'];
$this->description = $data['editor1'];
$this->description2 = '';
$this->color = $data['color'];
//$this->user_id = Auth::user()->id;
}
public static function fromRequest($request)
{
dump('inp=>',(new self ())->load($request->input()));
return (new self ())->load($request->input());
}
}
Please explain to me why I receive null while request->input() is an array, I call it from another place
$dto=GoodDto::fromRequest($request);
Method chaining, returns the last return from the chain. The other returns are used to call the next link in the chain.
(new self ())->load()
So load() needs to return $this
public function load($data)
{
...
return $this;
}
Currently it returns null, which is why it returns null.
See you are not saving the instance from the constructor, instead you pass it to load by enclosing it within the (....). By pass it I mean you call the load method on the return from the constructor.
You can test this like so:
class foo{
function load(){
return $this;//return this
}
}
var_dump((new foo)->load());
class bar{
function load(){
//return null
}
}
var_dump((new bar)->load());
Output
//return this
object(foo)#1 (0) {
}
//return null
NULL
sandbox
The second class in the example above class bar, is essentially what you are doing.
PS. forgot to scroll down on your post at first ... lol ... So I had to update my answer.
Bonus
You can also simplify the load code like this:
public function load($data)
{
foreach($data as $prop=>$value){
if(property_exists($this,$prop)) $this->$prop = $value;
}
return $this;
}
This way if you add new properties you don't have to edit the load method ever again, you just have to name the array elements the same as the class properties. You can even throw an error if the property does not exist if you want, by adding an else to the condition etc...
Personally, when I do this I prefer to call a set method like this:
//eg. $data = ['foo' => '2019-06-16']
public function load(array $data)
{
foreach($data as $prop=>$value){
$method = 'set'.$prop; //$method = 'setfoo' using the example above
if(method_exists($this,$method )){
$this->$method($value); //calls 'setfoo' with '2019-06-16'
}else{
throw new Exception('Unknown method '.$method);
}
}
return $this;
}
public function setFoo($date){
$this->foo = new DateTime($date);
}
Then you can apply some transforms to the data etc... PHP method names are not case sensitive. You can even combine these by first checking for a method then a property then throw the error etc...
Cheers.

Dependency injection an object without all of its methods

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.

Creating a new class object and setting variables directly - PHP

I am trying to understand how to efficiently create a new class object and set the variables directly.
I have a class:
class element_model
{
public $sType;
public $properties;
}
I have a controller in which the following function is defined:
public function create_element($sType, $properties)
{
$oElement_model = new element_model($sType, $properties);
return new element_model($sType, $properties);
}
But this does not returns a new element_model with properties set, it just returns an empty object.
It does not, however, throw an error.
What is the reason the function above does not work?
You have to pass to the constructor of the class, in PHP you should have a method in the class __construct :
class element_model
{
public $sType;
public $properties;
public function __construct($type, $property)
{
$this->sType = $type;
$this->properties = $property;
}
}
Then you can access them (note the variables are public)
$elem = new element_model($sType, $properties);
$elem->sType;
Although in some cases it is better to encapsulate vars (declare them private):
class element_model
{
private $sType;
private $properties;
public function __construct($type, $property)
{
$this->sType = $type;
$this->properties = $property;
}
public function getType()
{
return $this->sType;
}
public function getProperty()
{
return $this->properties;
}
}
Then you can access the variable through a getter
$elem = new element_model($sType, $properties);
$elem->getType(); //and
$elem->getProperty();
You must create a __construct function in your class that accepts the parameters and sets your variables. Like this:
class element_model{
.
.
.
public function __construct($type,$properties)
{
$this->sType = $type;
$this->properties = $properties;
}
}
The __construct function will be called when you create the object.
But if you want to be extra cool in programming, just define your properties as private and create getter and setter functions to access the variables of your object
private $sType;
public function getSType(){
return $this->sType;
}
public function setSType($value){
$this->sType = $value;
}

How to make multiple calls to class methods in the same line?

I have an issue in PHP.
In my php file, i created the following line:
$foo = $wke->template->notify()
->type("ERROR")
->errno("0x14")
->msg("You are not logged.")
->page("login.tpl");
In the end, I need my $foo variable will return this:
$foo->type = "ERROR"
$foo->errno= "0x14"
$foo->msg= "You are not logged."
$foo->page= "login.tpl"
Please note that the $wke->template is where i need call the notify() element.
The way of calling function of class one by one just by "->" because the function returning the same object of the class. See the example below. You will get this
class Wke {
public $type;
public $errno;
public $msg;
public $page;
public $template = $this;
public function notify(){
return $this;
}
public function errorno($error){
$this->errno = $error;
return $this; // returning same object so you can call the another function in sequence by just ->
}
public function type($type){
$this->type = $type;
return $this;
}
public function msg($msg){
$this->msg = $msg;
return $this;
}
public function page($page){
$this->page = $page;
return $this;
}
}
The whole magic is of return $this;
Each of those methods will need to return some object that stores what you set as the argument in it. Presumably, it will be the template that contains each object property on it, and when you call the method it sets that corresponding variable and returns itself.

Categories