2

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.

georg
  • 211,518
  • 52
  • 313
  • 390
Michel Tomé
  • 389
  • 2
  • 11

2 Answers2

3

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

php_nub_qq
  • 15,199
  • 21
  • 74
  • 144
  • 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. – Michel Tomé Sep 02 '14 at 11:30
  • So you would like to do method chaining, or just static calling? – Tibor B. Sep 02 '14 at 11:31
  • @MichelTomé why not just pass optional parameters to the `send()` method? – php_nub_qq Sep 02 '14 at 11:33
  • Both, it's kind of hard to explain... I want by calling `Mail::{something}` to have like a constructor call and then run the `{something}` function – Michel Tomé Sep 02 '14 at 11:33
  • @MichelTomé: I added your explanations to the question, I think it's clearer now. – georg Sep 02 '14 at 11:45
  • @php_nub_qq I suggested and edit to the code, does it work that way? – Michel Tomé Sep 02 '14 at 11:50
0

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();
George G
  • 7,443
  • 12
  • 45
  • 59