So i was wondering if there is a way to method chain, when the initial method is a static function. Here is what I mean:
class foo
{
public static function a()
{
$foo = new foo;
return $foo->bar();
}
public function bar()
{
return $this;
}
public function b()
{
return 1;
}
}
print foo::a()->b();
EDIT
print foo::a()->b(); not print foo:a()->b();
Static Methods or Other Methods, as long as the method is returning an object either self or some other, the methods can be chained, with the same method you are attempting.
class foo {
public function __construct() {
}
public function create() {
// create something;
return $this;
}
public function performSomethingElse() {
// perform something
return $this;
}
}
$object = new foo;
$object -> create() -> performSomethingElse();
this line
print foo:a();
should be
print foo::a();
and you will not be able to return $this in a static method
it needs to be instantiated first:
$foo = new Foo();
print $foo->a()->b();
Only sort of an answer, and somewhat idiosyncratic:
But I would advise that you have your object accompanied by a factory procedure instead:
class foo { .... }
function foo() { return new foo; }
This might remove some of the confusion for you. And it even looks a bit nicer by avoiding the mix of static and object method calls:
foo()->bar()->b();
It basically externalizes the static function. And your object only implements the chainable methods which return $this, or actual results.
Related
In PHP in order to define a callback a closure can be used and the tool for passing static parameters is the use directive.
class MyClass {
public function foo($x) {
echo $x;
}
public function bar() {
$x = '123';
$callback = function () use ($x) {
$this->foo($x);
};
$callback();
}
}
$myClass = new MyClass();
$myClass->bar();
Is it possible / How to avoid the anonymous function and replace it by a method?
class MyClass {
public function foo($x) {
echo $x;
}
public function baz() {
$x = '567';
// There is no function with the name create_user_func.
// Just to show, what I'm looking for.
$callback = create_callback([$this, 'foo'], $params = [$x]);
$callback();
}
}
$myClass = new MyClass();
$myClass->baz();
EDIT:
Some additional / backgroud info (to make clear, what I want to achieve and why -- and to avoid misanderstandings):
In my concrete case I need to pass the callback to a method of a framework. That means: I cannot / may not affect the way it gets called.
The method accepts only the callback itself, no arguments for the callback. That means, the callback has to "know"/provide the static parameters (and their values) it needs.
It's exactly, what the use directive solves. But I have multiple callback definitions in my method, and the method is getting long. So I want to move the logic of the callbacks to separate methods.
But I have multiple callback definitions in my method, and the method is getting long. So I want to move the logic of the callbacks to separate methods.
This is a perfect example for the magic method __invoke()
For each callback you need, extract the functionality and the properties it uses into a new class. Put the code into the __invoke() method of the new class, initialize all the properties it needs into its __construct() and you're ready to go.
The code:
class MyClass {
public function bar() {
$x = '123';
// Create the callback, pass the values it needs to initialize
$callback = new ActionFoo($x);
// Call the callback without arguments
$callback();
}
}
class ActionFoo {
private $x;
public function __construct($x) {
$this->x = $x;
}
public function __invoke() {
echo($this->x);
}
}
$myClass = new MyClass();
$myClass->bar();
I guess it's fair to say that you're trying to emulate Javascript's bind method. The problem with this in PHP is that functions are not first class citizens or objects, so something like ->bind($x) is not possible. There's also no way to pass additional parameters for a callable. So you're going to have to wrap it in something.
A more reusable method would be to write an appropriate class:
class CallbackWrapper {
protected $callable,
$args;
public function __construct(callable $callable, array $args) {
$this->callable = $callable;
$this->args = $args;
}
public function __invoke() {
call_user_func_array($this->callable, $this->args);
}
}
giveMeACallback(new CallbackWrapper([$this, 'foo'], [$x]));
Or you just simplify the construction of anonymous functions:
function make_callback(callable $callable, array $args) {
return function () use ($callable, $args) {
return call_user_func_array($callable, $args);
};
}
giveMeACallback(make_callback([$this, 'foo'], [$x]));
There are many ways to achieve this.
Using a helper function.
Code:
class MyClass {
private $x;
public function foo() {
echo $this->x;
}
public function bar() {
$this->x = '123';
anon($this);
}
}
$myClass = new MyClass();
$myClass->bar();
function anon($obj) {
$obj->foo();
}
Using call_user_func.
Code:
class MyClass {
private $x;
public function foo() {
echo $this->x;
}
public function bar() {
$this->x = '123';
call_user_func([$this, 'foo']);
}
}
$myClass = new MyClass();
$myClass->bar();
If for some reason you don't want to use member variables, you can pass the arguments with call_user_func_array.
Code:
class MyClass {
private $x;
public function foo($x) {
echo $x;
}
public function bar() {
$x = '123';
call_user_func_array([$this, 'foo'], [$x]);
}
}
$myClass = new MyClass();
$myClass->bar();
While reading this: http://propelorm.org/ I noticed that they are using -> sign on a static object and using several different methods of it as a "one-liner".
Or does the static object return an instance which from the methods are being called from?
What ever is the case I would like to read more about this. What is this called and does it really work with static objects?
I noticed that they are using -> sign on a static object
By static object you mean to say static method and that the code you are referring to is this:
classBookQuery::create()->findPK(123);
They are not using -> on a static method. They are using -> on the object returned by the static method.
You can try it yourself:
class AClass
{
public static function aMethod()
{
return new BClass();
}
}
class BClass
{
public function bMethod($int)
{
echo $int;
}
}
AClass::aMethod()->bMethod(123); // output: 123
As others have mentioned in the comments, the static function BookQuery::create() just returns another object.
The "arrow" operates on the returned object.
Example:
class Car {
public function beep() {
echo 'BEEP';
}
}
class CarProvider {
public static function get() {
return new Car();
}
}
// outputs 'BEEP';
CarProvider::get()->beep();
// the same as this
$car = CarProvider::get();
$car->beep();
This is oftentimes know as method chaining. The static method call is returning an instantiated object against which another method is called. This sort of construct is often achieve like this:
class myobject_factory {
public static function get_object () {
return new myobject;
}
}
class myobject {
protected $some_property;
public function set_some_property($value) {
$this->some_property = $value;
return $this;
}
public function get_some_propert() {
return $this->some_property;
}
}
$property = myobject_factory::get_object()->set_some_property('foobar')->get_some_property();
This is obviously a trivial example, but you can see how chaining is enabled because the setter on myobject returns $this.
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
I have good oop understanding but poor understanding of its implementation in php...
I have the following code, hope it's self documented =).
I need to have BB in the output
class A{
// I can't copy function::classname() to all my descendant classes
static function classname(){
echo __CLASS__;
}
}
class B extends A{
static function test(){
self::classname();
}
function test1(){
self::classname();
}
//i have A LOT of static and non-static functions using self::classname() in their code
// I can't copy all them to base class
}
$v = new B();
B::test();
$v->test1();
I'm stuck with static:: and self:: syntax
PS: another crazy question I've come across:
Suppose I have
function doSomething(){
echo $this->id;
}
Sometimes it gets into the static contexts. Yes, I know, that's because my bad application design. But is it possible to create a second(mirror, overloading) function
static function doSomething(){
echo false;
}
It means that using
$obj->doSomething() returns id and using Class::doSomething() returns false
Question 3:
Is it possible to get property default value in static context an property value in non-static context automatically?
Have a look at late static binding.
class A {
static function classname() {
echo __CLASS__;
}
static function test1() {
static::classname();
}
}
class B extends A {
static function classname() {
echo __CLASS__;
}
}
$v = new B();
B::test1();
$v->test1();
Or as pointed out by Long Ears in the comments, assuming php 5.3.0+ you can use get_called_class()
class A {
static function classname() {
echo get_called_class();
}
// this can be defined in either class A or B without affecting the output
static function test1() {
static::classname();
}
}
class B extends A {
}
$v = new B();
B::test1();
$v->test1();
Outputs:
BB
Regarding your second "crazy" question, see the Magic Methods. Basically, you would need to implement something like:
class Foo
{
public function __call($name, $arguments)
{
// call the _$name function
}
public static function __callStatic($name, $arguments)
{
// call the _{$name}_static function
}
private function _bar()
{
}
private static function _bar_static()
{
}
}
$foo = new Foo();
$foo->bar();
Foo::bar();
it's possible to add a static method like this
class Foo {
public static function __callStatic() {
// ....
}
}
// in Other file
// Call the static method
Foo-->__callStatic()
and call it on an other file (In php ) ?
How to call function of just created object without temporary variable?
Code
(new \Foo())->woof();
is not valid in php.
What is right?
$obj = new Foo();
$obj->woof();
If you have got PHP 5.4 or later, you can make use of a new feature:
Class member access on instantiation has been added, e.g. (new Foo)->bar().
You can do it like this, but it's not very clean:
<?php
class Foo
{
public function __construct()
{
}
public function bar()
{
echo 'hello!';
}
}
function Foo()
{
return new Foo();
}
Foo()->bar();
You could also change it to something like
function newClass($className)
{
return new $className();
}
newClass('Foo')->bar();
But the static method way is preferred.
It can work if the object has singleton
Foo::getInstance()->woof();
BTW: it doesn't have to be even singleton but also static method which returns the instance
class Foo {
public static function & getInstance()
{
return new self();
}
}