PHP: Method Chain with new self()? - php

I have an object created within a method, and I would like to further process it in another method of the same class.
I tried it like this, but $obj is not passed through to method two():
class SomeClass {
public static function one($id)
{
$obj = new self();
$obj->id = $id;
//...
return $obj;
}
public function two()
{
$obj->id = 2;
return $obj;
}
}
$obj = SomeClass::one($id)->two();
Is there a way to achieve this?
I found this thread How to chain method on a newly created object?, but it's still not quite clear whether this is possible or not.

two is a static method. You're trying to invoke it on an instance, and static methods by definition don't work on a specific instance.
Make the method not static, and manipulate $this instead of $obj.

If I'm not misunderstanding what you're trying to do, if you don't make the second method static, you can return an object and it'll be passed in as $this in the chained call;
class SomeClass {
public $id = 0;
public static function one($id)
{
$obj = new self(); // Create and return new object
$obj->id = $id;
return $obj;
}
public function two()
{
$this->id = 3; // The new object is $this here
return $this;
}
}
$obj = SomeClass::one(5)->two();

Method chaining only makes sense when you are using setters.
In combination with PHPDoc most IDE's (like NetBeans) will support code completion/autocomplete feature again.
p.s note that method chaining can give your more chance on errors like PHP Fatal error: Call to a member function .... on a non-object in .... when mixing in more classes with returning
class Example {
protected $var = null;
public function __construct() {
}
public function __destruct() {
unset($this->var); // explicit memory clearing
}
/**
* #return \Example
*/
public static function create() {
return new self();
}
/**
* #return \Example
*/
public static function getInstance() {
return self::create();
}
/**
* #return \Example
*/
public static function newInstance() {
return self::create();
}
/**
*
* #param mixed $var
* #return \Example
*/
public function setThing1($var) {
$this->var = $var;
return $this;
}
/**
*
* #param mixed $var
* #return \Example
*/
public function setThing2($var) {
$this->var = $var;
return $this;
}
}
Example::create()->setThing1(1)->setThing2('2');

Related

PhpStorm dynamic type hinting class property

I'm using a builder pattern to create an object, call methods, and return back to the calling object.
class Caller{
public function invoke() {
new Builder($this)->setColor('red')->setSize(5)-> // need typehint for Caller to return here
}
public function next() {
}
}
class Builder{
/**
* #var ????
*/
private $caller;
/**
* #param ???? $caller
*/
public function __construct($caller) {
$this->caller = $caller;
}
public function setColor($color) {
$this->color = $color;
return $this;
}
/**
* #param int $size
* #return ????
*/
public function setSize($size) {
$this->size = $size;
return $this->caller;
}
}
There is a way to invoke a parent method and return the child typehints by specifying $this as the return type in the parent class, but how can I reference a separate class type stored in $this->caller as the return type and get the typehints?

Static method that calls itself on an object

I want to have a class that i can use it this way:
Thing::doThis()->doThat()->doImportantThing();
OR
Thing::doThat()->doImportantThing();
OR
Thing::doImportantThing();
But currently i can only use it this way:
$thing = new Thing();
$thing->doThis()->doThat()->doImportantThing();
What do i have to change in the class so i can use it the way i want? I already return a Thing instance in every function call.
I want to use that for a simple reason, imagine a mail class, in the constructor you define a default from and to, but you might want to change it, so you do Mail::setFrom()->send(). If you want to change the to, you use Mail::setTo()->send(). It just makes it easier to use if it's going to be used in different projects by different people.
I want by calling Mail::{something} to have like a constructor call and then run the {something} function.
You can do this
class Thing {
public static function __callStatic($name, $arguments){
$thing = new self;
return $thing->$name($arguments);
}
public function __call($name, $arguments){
return $this->$name($arguments);
}
private function doThis(){
echo 'this'.PHP_EOL;
return $this;
}
private function doThat(){
echo 'that'.PHP_EOL;
return $this;
}
private function doImportantThing(){
echo 'Important'.PHP_EOL;
return $this;
}
}
Thing::doThis()->doThat();
Thing::doThat()->doImportantThing();
It is a really ugly work-around, though. And it disables you to have private methods.
DEMO
One great thing for static methods is that they can work in object context, and can be called like this: $instance->staticMethod()
Here it is (even you get code completion in ide, and works as axpected as you want):
class Mail
{
public static $from;
public static $to;
public static $subject;
public static $message;
protected static $onlyInstance;
protected function __construct ()
{
// disable creation of public instances
}
protected static function getself()
{
if (static::$onlyInstance === null)
{
static::$onlyInstance = new Mail;
}
return static::$onlyInstance;
}
/**
* set from
* #param string $var
* #return \Mail
*/
public static function from($var)
{
static::$from = $var;
return static::getself();
}
/**
* set to
* #param string $var
* #return \Mail
*/
public static function to($var)
{
static::$to = $var;
return static::getself();
}
/**
* set subject
* #param string $var
* #return \Mail
*/
public static function subject($var)
{
static::$subject = $var;
return static::getself();
}
/**
* set message
* #param string $var
* #return \Mail
*/
public static function message($var)
{
static::$message = $var;
return static::getself();
}
public static function send()
{
echo "<pre><b>Hurrah mail sent</b>"
. "\nFrom:\t ".static::$from.""
. "\nTo:\t ".static::$to." "
. "\nSubject: ".static::$subject.""
. "\nMessage: ".static::$message;
echo "</pre>";
}
}
Example usage:
Mail::from('george#garcha')
->to('michel#tome')
->subject('hehe works')
->message('your welcome')
->send();
Output
Hurrah mail sent
From: george#garcha
To: michel#tome
Subject: hehe works
Message: your welcome
Example 2 (this also works):
Mail::from('george#garcha')
->to('michel#tome');
Mail::subject('hehe works')
->message('your welcome')
->send();

How to define a static property in PHP?

Here is my source:
class Test {
public static function a() {
$share_var = ClassConfig::getVarA(); // return a hardcoding const 10;
// echo $share_var;
// ...
}
}
public static function b() {
$share_var = ClassConfig::getVarA(); // return a hardcoding const 10;
// echo $share_var;
// ...
}
}
}
So $share_var = ClassConfig::getVarA(); is called twice. So I do something like this:
class Test {
private static $share_var = ClassConfig::getVarA(); // return a hardcoding const 10;
public static function a() {
// echo $share_var;
// ...
}
}
public static function b() {
// echo $share_var;
// ...
}
}
}
But it failed.
How can I do that.
You can define the property as static, but it's no option for you because you can't call a method during class variable definition
class TestA {
private static $share_var_private = 10; // You can do this, but you can't call another method here eg TestB::a();
private static $share_var_private = Config::getA(); // This won't work
public static function a() {
echo self::$share_var_private;
}
}
If you want static methods, then you need something like own initialize method which will initialize the property but it has its disadvantages.
/**
* This is example of what I've described, but it is not so good for usage because you have to call init() method before you can use the class. You could call init method in each class method, but you can imagine it wouldn't be nice.
*/
class TestWithInit {
/**
* When it's defined as static, it can't be defined as private in php
*/
private static $share_var_static; // You can't call another class here eg TestB::a();
public static function init() {
self::$share_var_static = Config::getVarA();
}
public static function a() {
echo self::$share_var_static;
}
public static function b() {
echo self::$share_var_privat; // This would also work ... calling private variable as static (::)
}
}
Better option is probably singleton pattern which is instance of class but just once and is some ways it's quite close to static methods(NOT SAME).
class TestSingleton {
/**
* Singleton instance
*
* #var TestSingleton
*/
private $instance = null;
/**
* My special config value
*/
private $share_var;
/**
* For singleton make construct private
*/
private function __construct() {
// You can now initialize this private variable in constructor
self::$share_var = Config::getVarA();
}
/**
* Returns instance of this class
*
* #return TestSingleton
*/
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self(); // also new TestSingleton() woudl work
}
// return the instance
return self::$instance;
}
/**
* See this method is not static anymore
*/
public function a() {
echo $this->share_var_static;
}
/**
* See this method is not static anymore
*/
public function b() {
echo $this->share_var_static;
}
}
// Then you would call the method as:
TestSingleton::getInstance()->a();
TestSingleton::getInstance()->b();
// or
$myInstance = TestSingleton::getInstance();
$myInstance->a();
$myInstance->b();
Next option is to use normal non-static methods and object instance, and initialization of the object property in constructor, but I guess you know how.
I assume you wanted something more like static...
You must use self:
class Test {
private static $share_var = 'Something';
public static function a() {
echo self::$share_var;
}
public static function b() {
echo self::$share_var;
}
}
Test::a();
Test::b();
class Test {
private $share_var = ClassConfig::getVarA();
public static function a() {
echo $this->share_var;
}
public static function b() {
echo $this->share_var;
}
}
if you want to learn more about static Keyword, you can click the followed link, it's detail: static keyword

Netbeans Intellisense PHP Iterator Interface

I'm using Netbeans 6.9 and writing a PHP class that implements the Iterator interface. I would like to have the IDE offer Intellisense as I iterate over the items in my object. It seems to work for the Zend Framework as I've noticed that when iterating over a Zend_Db_Rowset I get intellisense for a Zend_DB_Row. For example, when I write:
foreach($rowset as $row) {
$row->delete();
}
When I type "$row->" Netbeans pops up its code hints for the member functions of Zend_Db_Row_Abstract. Unfortunately, I can't get this to work for my own code. Below is a sample I tried to get to work:
class Foo {
private $value;
/**
*
* #param string $value
*/
public function setValue($value) {
$this->value = $value;
}
/**
*
* #return string
*/
public function getValue() {
return $this->value;
}
}
class It implements Iterator {
private $data;
public function __construct($data) {
$this->data = $data;
}
/**
*
* #return Foo
*/
public function current() {
return current($this->data);
}
/**
*
* #return Foo
*/
public function key() {
return key($this->data);
}
/**
*
* #return Foo
*/
public function next() {
return next($this->data);
}
/**
*
* #return Foo
*/
public function rewind() {
return reset($this->data);
}
/**
*
* #return bool
*/
public function valid() {
return key($this->data) !== null;
}
}
$a = new Foo();
$b = new Foo();
$a->setValue('Hello');
$b->setValue('Bye');
$testData = array($a, $b);
$myIt = new It($testData);
foreach ($myIt as $obj) {
echo $obj->getValue();
}
Strangely the intellisense seems to think $obj is an object of type It when I want it to think (and it actually is) an object of type Foo.
Within the body of the loop you can provide the type hint in a comment.
/* #var $obj Foo */
+1 for Brian Fisher's suggestion.

How to implement this feature in PHP?

When accessing member that doesn't
exist, automatically creates the
object.
$obj = new ClassName();
$newObject = $ojb->nothisobject;
Is it possible?
Use the magic overloading functions
You can achieve this kind of functionality with Interceptor __get()
class ClassName
{
function __get($propertyname){
$this->{$propertyname} = new $propertyname();
return $this->{$propertyname}
}
}
Though example in the previous post will work just fine also when the attribute is changed to public so you can access it from outside.
If you mean lazy initalization, this is one of many ways:
class SomeClass
{
private $instance;
public function getInstance()
{
if ($this->instance === null) {
$this->instance = new AnotherClass();
}
return $this->instance;
}
}
$obj = new MyClass();
$something = $obj->something; //instance of Something
Use the following Lazy loading pattern:
<?php
class MyClass
{
/**
*
* #var something
*/
protected $_something;
/**
* Get a field
*
* #param string $name
* #throws Exception When field does not exist
* #return mixed
*/
public function __get($name)
{
$method = '_get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->{$method}();
}else{
throw new Exception('Field with name ' . $name . ' does not exist');
}
}
/**
* Lazy loads a Something
*
* #return Something
*/
public function _getSomething()
{
if (null === $this->_something){
$this->_something = new Something();
}
return $this->_something;
}
}

Categories