Commonly, in a lot of frameworks, you can find examples of creating a query using the query builder. Often you will see:
$query->select('field');
$query->from('entity');
However, in some frameworks you can also do it like this
$object->select('field')
->from('table')
->where( new Object_Evaluate('x') )
->limit(1)
->order('x', 'ASC');
How do you actually do this kinds of chains?
This is called Fluent Interface -- there is an example in PHP on that page.
The basic idea is that each method (that you want to be able to chain) of the class has to return $this -- which makes possible to call other methods of that same class on the returned $this.
And, of course, each method has access to the properties of the current instance of the class -- which means each method can "add some information" to the current instance.
Basically, you have to make every method in the class return the instance:
<?php
class Object_Evaluate{
private $x;
public function __construct($x){
$this->x = $x;
}
public function __toString(){
return 'condition is ' . $this->x;
}
}
class Foo{
public function select($what){
echo "I'm selecting $what\n";
return $this;
}
public function from($where){
echo "From $where\n";
return $this;
}
public function where($condition){
echo "Where $condition\n";
return $this;
}
public function limit($condition){
echo "Limited by $condition\n";
return $this;
}
public function order($order){
echo "Order by $order\n";
return $this;
}
}
$object = new Foo;
$object->select('something')
->from('table')
->where( new Object_Evaluate('x') )
->limit(1)
->order('x');
?>
This is often used as pure eye candy but I suppose it has its valid usages as well.
class c
{
function select(...)
{
...
return $this;
}
function from(...)
{
...
return $this;
}
...
}
$object = new c;
Related
Say I have the following class:
class Test
{
private static $instance = false;
public static function test()
{
if(!self::$instance)
{
self::$instance = new self();
}
return self::$instance;
}
public function test1()
{
//...
}
public function test2()
{
//...
}
}
And I go about calling functions by chaining them like so:
$data = Test::test(...)->test1(...)->test2(...);
At the moment for the above method chain to work I have to keep returning $instance and I really would like it if I could return something from test2() to then be assigned to $data but I am not sure how to do this as I have to keep returning $instance in order for mt method chain to work?
If you want to chain methods, you need to return the current instance from any method which has another call chained on after it. However, it's not necessary for the last call in the chain to do so. In this case that means you're free to return whatever you like from test2()
Just bear in mind, if you return something different from test2() you'll never be able to chain anything onto it in future. For example, $data = Test::test(...)->test2(...)->test1(...); wouldn't work.
Protip: it's worth documenting your code with some comments explaining which ones are and aren't chainable so you don't forget in future.
Generally speaking if you are doing method chaining, and I'm assuming each of the tests above return your data model in a different state, and I assume that you want some data from the model itself. I would do the following:
class Test
{
private static $model;
public function test1() {
//do something to model
return $this;
}
public function test1() {
//do something to model
return $this;
}
public function finish_process() {
//process results
return $this.model;
}
}
so essentially i can do the following now:
$results = Test::test1()->finish_process();
and
$results = Test::test1()->test2()->finish_process();
You can pass the $data by its reference and you can change it or assign any data into it.
// inside class
public function test2( &$data ) {
$data = 'it will work';
}
// outside class
$data = '';
Test::test(...)->test1(...)->test2($data);
check this http://php.net/manual/en/language.references.pass.php
return $this inside test1() and test2() methods.
I am testing the way writing PHP like js, and I wonder if this will be possible.
If say I have A, B function in Class C.
Class C{
function A(){
}
function B(){
}
}
$D = new C;
$D->A()->B(); // <- Is this possible and how??
In Js, we can simple write like D.A().B();
I tried return $this inside of function A(), didnt work.
Thank you very much for your advice.
What you are looking for is called fluent interface. You can implement it by making your class methods return themselves:
Class C{
function A(){
return $this;
}
function B(){
return $this;
}
}
Returning $this inside the method A() is actually the way to go.
Please show us the code that supposedly didn't work (there probably was another error in that code).
Its rather simple really, you have a series of mutator methods that all returns the original (or other) objects, that way you can keep calling functions.
<?php
class fakeString
{
private $str;
function __construct()
{
$this->str = "";
}
function addA()
{
$this->str .= "a";
return $this;
}
function addB()
{
$this->str .= "b";
return $this;
}
function getStr()
{
return $this->str;
}
}
$a = new fakeString();
echo $a->addA()->addB()->getStr();
This outputs "ab"
Returning $this inside the function allows you to call the other function with the same object just like jQuery does.
I tried it and it worked
<?php
class C
{
public function a() { return $this; }
public function b(){ }
}
$c = new C();
$c->a()->b();
?>
i have seen in some libraries something like this :
$this->getResponse()->setRedirect($returnUrl);
How is this 'multicall' done, or, how should the class be build to do something like this?
I think :
class greeting
{
public function hi()
{
public function howAreYou()
{
echo 'How are you?';
}
}
}
$greet = new greeting;
$greet->hi()->howAreYou();
But i think it's not so good, i would better use something like extends, but i don't know. Thx for your suggestions.
If this is a class instance calling itself, it is called "method chaining".
In PHP, can be done by using return $this; note that this is a very different mechanism than class inheritance - it doesn't really make sense to treat them as interchangeable.
See also: https://stackoverflow.com/search?q=method+chaining+php
getResponse() is returning a class instance which has a setRedirect() method.
Example:
class Foo
{
public function getResponse()
{
$redirect = new Bar();
return $redirect;
}
}
class Bar
{
public function setRedirect($returnUrl)
{
// do something
}
}
$foo = new Foo();
$foo->getResponse()->setRedirect("returnUrl");
No.
All you have to do is return self at very end of each function.
So Your example would be like>
class greeting
{
public function hi()
{
echo "Hi";
return $this;
}
public function howAreYou()
{
echo 'How are you?';
return $this;
}
}
$greet = new greeting;
$greet->hi()->howAreYou();
Or even:
$greet->hi()->howAreYou()->hi()->howAreYou();
class stutter{
public function a(){
echo 'h';
return $this;
}
public function b(){
echo 'hello world!';
}
}
$var=new stutter();
var->a()->b();
Output is:
h hello world
Chaining methods is not the same as declaring functions within a method... in fact the latter will spit an error (not the function declaration, but the way you're calling it). In order to chain a method, just have it return the object itself:
Class chainableObject
{
public $name=null;
public function __construct($name='')
{
$this->name=$name;
return $this;
}
public function setName($name)
{
$this->name = $name;
return $this;//makes chainable
}
public function greet()
{
echo 'Hello, '.$this->name;
return $this;
}
}
$chain = new chainableObject('Frank')->greet();//outputs: Hello, frank
The explanation: All methods return the instance itself, so basically, read the last line of the snippet like this [create object with name:Frank]=>call method greet on the return value of this action. Since the return value is $this, the object that has a greet method, that's what will happen... easy, for more info: just google php method chaining
In PHP it's not possible to return self to chain static methods. This limits the usage of static methods, because chaining is pretty useful and you have to use instances to chain methods.
Are there any reasons why the PHP developers decided not to allow returning self? Or is it not possible to return self in OOP in general?
Try return new static() or return new self():
class Calculator
{
private static $_var = 0;
public static function startFrom($var)
{
self::$_var = $var;
return new static();
}
public static function add($var)
{
self::$_var += $var;
return new static();
}
public static function sub($var)
{
self::$_var -= $var;
return new static();
}
public static function get()
{
return self::$_var;
}
}
This could be used for chain static methods:
echo Calculator::startFrom(10)
->add(5)
->sub(10)
->get(); // return 5
New self vs. new static
I cannot give you a reason why other than the syntax itself isn't supported. It almost could work in PHP 5.3:
class Foo
{
public static function A()
{
return __CLASS__;
}
public static function B() { }
}
$chain = Foo::A();
$chain::B();
If PHP would parse Foo::A()::B() then it would work.
You can't return a 'self' because no OOP language I know allows to return a type as a type (don't know how to rephrase that). However everyone allows to returns an instance of a type. A static method is part of a class definition and it is callable as long as the application runs.
When doing OOP, you should use the static keyword very carefuly, as it's very easy to abuse it. If you want to chain methods then use an object. Static methods should be used only when no state is required and the function simply process an input and returns a result.
When chaining you have to maintain state and that's where you don't use static classes/methods at all (ok there are some cases but those are exceptions and it's not the case here).
If you really had to, you can use self::class:
class Foo
{
public static function returnSelfClass(): string
{
return self::class;
}
}
You can even use static::class for late static binding:
class Bar
{
public static function returnStaticClass(): string
{
return static::class;
}
}
class Baz extends Bar
{
}
For instance:
Foo::returnSelfClass()::returnSelfClass(); // Works
echo Baz::returnStaticClass(); // Prints "Baz"
In PHP 7.0 forward, this works
class test {
public static function a(){
echo 1;
return __CLASS__;
}
public static function b(){
echo 2;
return __CLASS__;
}
}
test::a()::b();
If somebody that had no relationship to you asked you to give up yourself and return yourself to something that didn't exist how would you feel?
I have seen many php scripts in which you can cascade class method to produce a specific functionality for example as in codeigniter when you load a view you would type
<?php
class Posts extends Controller
{
function index() {
$this->load->view("BlaBla");
}
}
?>
I am not completely sure if these are cascaded methods or what butI don't have enough experience to hack the codeigniter core and figure out myself.
Can anyone tell me how to do this or guide me to some tutorial or so
Every method must return its class instance, like:
class A{
function B(){
//do stuff
return $this;
}
function C(){
//do stuff
return $this;
}
function D(){
return $this->B()->C()->B()->B()->C();
}
}
or you can build your own cahining class to chain anything:
class Ch{
static private $i;
public static function i($arg){
if (!self::$i instanceof self){
self::$i = new self();
}
self::$i->data=$arg;
return self::$i;
}
function __call($name,$args){
array_unshift($args,$this->data);
$this->data=call_user_func_array($name,$args);
return $this;
}
function get(){
return $this->data;
}
}
echo Ch::i('Hello world')->trim('Hld')->str_repeat(5)->substr(5,7)->strtoupper()->get();