I don't truly understand how chaining functions work on the values that are returned.
Let's say I have a function that returns a string or array
public static $query;
public static function getArray($arr) {
Database::$query = $arr;
return Database::$query;
}
public function single() {
return Database::$query[0];
}
Why, when I call it can I then not chain a function onto this to affect the string (In this example I was to append ' test' and how would I go about doing this?
Why can I simply not call
Database::getArray(array("test","test2"))->single();
Without getting a Call to a member function single() on array error. But instead, make it return only the first value of the array.
How would I go append doing what I'm trying to achieve here? Why is my logic wrong?
When you call a method, the return value is whatever that method decides to return; the return value doesn't have any automatic relationship with the object you called the method on. For instance:
class A {
public function foo() {
return 'Hello, World!';
}
}
$a = new A;
echo $a->foo();
The value returned is just an ordinary string, just as if foo was a global function not attached to any object.
In PHP, strings (and other "basic types" like arrays) are not objects, so you can't call any methods on them. Even if you could, those methods would be built into the language, and you couldn't just decide that ->single() could be called on any array.
What may be confusing is that some people write methods with the convention that they return an object, known as a "fluent interface", or more generally "chained methods". This is not a feature of the language, just a natural consequence of returning an object from a method:
class A {
public function foo() {
return new B;
}
}
class B {
public function bar() {
return 'Hello, World!';
}
}
$a = new A;
$b = $a->foo(); // $b is a B object
echo $b->bar();
// We can combine this into one line:
echo (new A)->foo()->bar();
There is nothing special about this chaining; it's just that wherever you have an object, you can call appropriate methods on it, just as wherever you have a number, you can do maths with it. Compare with a simple addition:
function foo() {
return 1;
}
$a = foo();
$a = $a + 2;
echo $a;
// We can combine this into one line:
echo foo() + 2;
// Or keep the assignment:
$a = foo() + 2;
echo $a;
The object doesn't know it's being chained - in fact, it shouldn't need to know anything about the code around it, and that's an important part of structured programming.
A common pattern is then to have modifying methods which return the object they just modified, so you can make a series of modifications in one go:
class A {
private $words = [];
public function addWord($word) {
$this->words[] = $word;
// $this is the current object, which is an instance of class A
return $this;
}
public function getString() {
return implode(' ', $this->words);
}
}
$a = new A;
// Calling $a->addWord(...) gives us back the same object
$a = $a->addWord('Hello');
$a = $a->addWord('World');
// Calling $a->getString() gives us back a string
echo $a->getString();
// We can combine this into one line:
echo (new A)->addWord('Hello')->addWord('World')->getString();
Note that you can only refer to $this if you have created an instance of the object (with the new keyword), not in a method declared as static. A static method can still have this kind of pattern, but it will need to return some other object, like new self (a new instance of the current class) or self::$foo (an object created earlier).
it's called fluent interface, if you want to chain methods from same class you have to return this from each of them which you want to call fluently, so your code should look like:
public static $query;
public function getArray($arr) {
Database::$query = $arr;
return $this;
}
public function single() {
return Database::$query[0];
}
after applying changes, the construct Database::getArray(array("test","test2"))->single(); will work, however you may consider renaming method getArray, because as its name suggests, it shouldn't be returning $this, but array
#EDIT
you should change the type of function getArray from public static function to public function to make it work, also your final statement will change to something like:
(new Database())->getArray(array("test","test2"))->single();
however, in this case, I would consider redesigning your class and creating some kind of singleton so that you instantiate Database class only once and store the object somewhere
Related
I want to include this function in a class. This function will essentially json_encode the output of the previous function (I hope that makes sense).
I want to do something like this:
<?php
$app = new App;
// $app->error(); // Should return ['some error', 'some other error']
echo $app->error()->encode(); // Should return {'errors': ['some error', 'some other error']}.
Also what's the correct term for such function? I've been searching but couldn't find anything as I didn't really know what I was looking for.
Thanks!
Edit
I think you got that wrong. It's my mistake I didn't mention it before.
That's just an example. Just like in frameworks like Slim, where you can do something like:
$response->getBody()->write('Something');
I want to do something similar to that. Not just that. I want to learn how it's done.
Here is some boilerplate code you could use. The idea is that you should make the error method return an object of yet another class. That object should then in turn have the encode method.
In your example, you want $app->error() to return an array. For it to behave as an array, we can extend the ArrayObject class.
Secondly, you want that same $app->error() to expose another method encode. So you define that method in that same class mentioned above:
// Extend ArrayObject to make objects behave as arrays
class ErrorMsg extends ArrayObject {
// Add method to return JSON string
public function encode() {
return json_encode(array("errors" => $this->getArrayCopy()));
}
}
class App {
private $error;
public function doSomething() {
// For demo sake, just set an error:
$this->error = ["An error occurred in doSomething", "No further info"];
}
public function error() {
// This is the key: instantiate and return another object
return new ErrorMsg($this->error);
}
}
$app = new App;
// Set an error condition in $app
$app->doSomething();
// Loop over error array
foreach ($app->error() as $index => $error) {
// Display the error
echo "Error $index is: $error\n";
}
// Display the JSON encoding of the same.
echo $app->error()->encode() . "\n";
Output:
Error 0 is: An error occurred in doSomething
Error 1 is: No further info
{"errors":["An error occurred in doSomething","No further info"]}
See it run on eval.in
General idea to chain method calls
In general, when you want your objects to support chained -> notation, you must make sure to define each method as returning yet another object with its own methods. Then those methods can again return objects, with again exposed methods, etc. And so you can chain-call on and on.
So if you want to be able to write:
$a = new A();
$result = $a->b()->c()->d();
...then your code would look something like this:
class D {
// ...
}
class C {
private $d;
public function C() { // constructor
$this->d = new D();
}
public function d() {
return $this->d;
}
}
class B {
private $c;
public function B() { // constructor
$this->c = new C();
}
public function c() {
return $this->c;
}
}
class A {
private $b;
public function A() { // constructor
$this->b = new B();
}
public function b() {
return $this->b;
}
}
Of course, this is just the structure, and you'd pass some specific data to either the constructors and/or methods. But the main idea is that you never return simple types (String, Number, ...), but always objects.
I saw different articles about chain method, but I still don't understand the difference between "return $this" and "return $this->SomeVariable".I also want to know how a method call another method within and without the class too.
Could someone kindly explain it ?
thanks you!
My example, it echo "bca", but I dont get why "a" is the last to display...
class validation {
public function __construct($a) {
$this->a = $a;
}
public function one($a) {
echo $a = "b";
return $this;
}
public function two($a) {
echo $a = "c";
return $this->a;
}
}
$a = "a";
$NameErr = new validation($a);
echo $NameErr->one($a)->two($a);
It is returned from two($a) since it returns $this->a that is set in constructor as "a", and method one($a) returns instance of the object on which is then called function two.
$this refers to the object instance. So difference is that return $this->SomeVariable it just returns the variable.
Also just a nice coding tip. Declare $a in class as private variable like this:
class Validation
{
private $a;
}
First let me say
$this refers to the class you are in.
This way of coding is called fluent interface. return $this returns the current object,
$NameErr->one($a)->two($a);
is same as
$NameErr->one($a);
$NameErr->two($a);
And in this case
First the method one() is called,
thus the value b is printed and the object of the class is returned.
Now method two() is called,
the value c is echoed out and the property is returned, which is echoed out side the class.
ps: Declaring the variable $a as private would be a nice practice.
I was looking to some php codes, and I saw an object that will call multiple methods in the same line.
I've tried to understand how to do it, and why we need to use it?
$object->foo("Text")->anotherFoo()->bar("Aloha")
What this styling called? and what is the best way to use it in php applications.
This syntax is called method chaining, and it's possible because each method returns the object itself ($this). This is not necessarily always the case, it's also used to retrieve an object's property that in turn also can be an object (which can have properties that are objects, and so on).
It is used to reduce the amount of lines that you need to write code on. Compare these two snippets:
Without chaining
$object->foo("Text");
$object->anotherFoo();
$object->->bar("Aloha");
Using method chaining
$object->foo("Text")->anotherFoo()->bar("Aloha");
this is used when the first function returns an object that will contains the second function that will return another object and so on...
class X
{
public function A()
{
echo "A";
}
public function B()
{
echo "B";
}
}
class Y
{
public function A()
{
echo "Y";
}
public function B()
{
return $this;
}
}
$y = new Y();
$y->B()->A();//this will run
$x = new X();
$x->A()->B();//this won't run, it will output "A" but then A->B(); is not valid
How can I do multiple levels of de-referencing? For instance, in C#, we can keep appending a '.' to access the next objects properties: string s, s.ToString(), s.ToString().ToUpper(). With PHP, I get to around $this->someobject, but $this->someobject->somethingelse does not appear to work.
Any ideas?
Assuming you're using PHP5+, and $this->someobject returns an object with a property called somethingelse; it should work.
Similarly, this also works
class Example
{
public function foo()
{
echo 'Hello';
return $this; // returning an object (self)
}
public function bar()
{
echo ' World';
return $this;
}
}
$example = new Example;
$example->foo()->bar(); // Hello World
$example->foo()->foo()->foo()->bar()->foo(); // HelloHelloHello WorldHello
Edit:
Just as a further note, you don't have to return self. Any object will suffice.
class Example1
{
public function __construct(Example2 $example2)
{
$this->example2 = $example2;
$this->example2->setExample1($this);
}
public function foo()
{
echo 'Hello';
return $this->example2;
}
}
class Example2
{
public function setExample1(Example1 $example1)
{
$this->example1 = $example1;
}
public function bar()
{
echo ' World';
return $this->example1;
}
}
$example = new Example1(new Example2());
$example->foo()->bar(); // Hello World
$example->foo()->bar()->foo()->bar(); // Hello WorldHello World
PHP's dereference operator only works on Objects; and, unlike some other languages, only Objects are objects ;) Primitives don't have an implicit wrapper. So, if $this->someobject resolves to a non object, (like a string, float, int or array), you cannot chain the dereference operator any further.
You have the syntax correct, but only for nested objects. Frequently, an object property might be of the array type, so you would need to access it accordingly: $this->somearray['somekey'];
If you're looking to create a fluent interface to allow for chaining, the object methods would need to return $this; in order to facilitate that.
Classes can also be accessed with the :: (scope resolution operator) without being instantiated, but that's a little outside of the scope of the question.
Hope that helps!
I can't quite understand why the output of this code is '1'.
My guess is that php is not behaving like most other OO languages that I'm used to, in that the arrays that php uses must not be objects. Changing the array that is returned by the class does not change the array within the class. How would I get the class to return an array which I can edit (and has the same address as the one within the class)?
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function getArr()
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = $t->getArr();
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
EDIT: I expected the output to be 0
You have to return the array by reference. That way, php returns a reference to the array, in stead of a copy.
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function & getArr() //Returning by reference here
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = &$t->getArr(); //Reference binding here
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
This returns 0.
From the returning references subpage:
Unlike parameter passing, here you have to use & in both places - to
indicate that you want to return by reference, not a copy, and to
indicate that reference binding, rather than usual assignment, should
be done
Note that although this gets the job done, question is if it is a good practice. By changing class members outside of the class itself, it can become very difficult to track the application.
Because array are passed by "copy on write" by default, getArr() should return by reference:
public function &getArr()
{
return $this->arr;
}
[snip]
$tobj_arr = &$t->getArr();
For arrays that are object, use ArrayObject. Extending ArrayObject is probably better in your case.
When you unset($tobj_arr[0]); you are passing the return value of the function call, and not the actual property of the object.
When you call the function again, you get a fresh copy of the object's property which has yet to be modified since you added 5 to it.
Since the property itself is public, try changing:
unset($tobj_arr[0]);
To: unset($t->arr[0]);
And see if that gives you the result you are looking for.
You are getting "1" because you are asking PHP how many elements are in the array by using count. Remove count and use print_r($tobj_arr_fresh)