开发者

Global PHP functions chaining through a Class

Is it possible to chain all PHP f开发者_如何学运维unctions through an object/class?

I have this on my mind and I imagine it something like this:

$c = new Chainer();

$c->strtolower('StackOverFlow')->ucwords(/* the value from the first function argument */)->str_replace('St', 'B', /* the value from the first function argument */);

this should produce:

Backoverflow

Thanks.


Have a look at:

http://php.net/manual/en/language.oop5.magic.php

especially:

http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods

and propably:

http://php.net/manual/en/function.call-user-func-array.php

As so many posted their examples, I'll try too:

<?php
class Chainer
{
    protected $buffer = null;

    public function __call($name, $args) {
        if (method_exists($this, $name)) {
            $this->buffer = call_user_func_array(array($this, $name), $args);
        }
        elseif (function_exists($name)) {
            if ($this->buffer !== null) {
                $args[] = $this->buffer;
            }

            $this->buffer = call_user_func_array($name, $args);
        }

        return $this;
    }

    public function strpos($needle, $offset = 0) {
        return strpos($this->buffer, $needle, $offset);
    }

    public function __toString() {
        return (string)$this->buffer;
    }
}

$c = new Chainer();
echo $c->strtolower('StackOverFlow')->ucwords()->str_replace('St', 'B')->strpos('overflow'); // output: 4


Do you mean to do str_replace('St', 'B', ucwords(strtolower('StackOverFlow'))) ?

The methods you are calling above are functions, not methods tied to any class. Chainer would have to implement these methods. If this is what you want to do (perhaps for a different purpose and this is just an example) your implementation of Chainer might look like this:

class Chainer {
   private $string;
   public function strtolower($string) {
      $this->string = strtolower($string);
      return $this;
   }
   public function ucwords() {
      $this->string = ucwords($this->string);
      return $this;
   }
   public function str_replace($from, $to) {
      $this->string = str_replace($from, $to, $this->string);
      return $this;
   }
   public function __toString() {
      return $this->string;
   }
}

This would work in your above example somewhat, but you would call it like this:

$c = new Chainer;
echo $c->strtolower('StackOverFlow')
   ->ucwords()
   ->str_replace('St', 'B')
; //Backoverflow

Note that you never get the value of /* the value from the first function argument */ back out from the chain as this wouldn't make sense. Maybe you could do it with a global variable, but that would be quite hideous.

The point is, you can chain methods by returning $this each time. The next method is called on the returned value which is the same object because you returned it (returned $this). It is important to know which methods start and stop the chain.

I think that this implementation makes the most sense:

class Chainer {
   private $string;
   public function __construct($string = '') {
      $this->string = $string;
      if (!strlen($string)) {
         throw new Chainer_empty_string_exception;
      }
   }
   public function strtolower() {
      $this->string = strtolower($this->string);
      return $this;
   }
   public function ucwords() {
      $this->string = ucwords($this->string);
      return $this;
   }
   public function str_replace($from, $to) {
      $this->string = str_replace($from, $to, $this->string);
      return $this;
   }
   public function __toString() {
      return $this->string;
   }
}
class Chainer_empty_string_exception extends Exception {
   public function __construct() {
      parent::__construct("Cannot create chainer with an empty string");
   }
}

try {
   $c = new Chainer;
   echo $c->strtolower('StackOverFlow')
      ->ucwords()
      ->str_replace('St', 'B')
   ; //Backoverflow
}
catch (Chainer_empty_string_exception $cese) {
   echo $cese->getMessage();
}


You can do this provided the Chainer class looks something like

class Chainer
{
    private $string;

    public function __construct($string = null)
    {
        $this->setString($string);
    }

    public function setString($string)
    {
        $this->string = $string;
        return $this;
    }

    public function __toString()
    {
        return $this->string;
    }

    public function strtolower($string = null)
    {
        if (null !== $string) {
            $this->setString($string);
        }
        $this->string = strtolower($this->string);
        return $this;
    }

    public function ucwords($string = null)
    {
        if (null !== $string) {
            $this->setString($string);
        }
        $this->string = ucwords($this->string);
        return $this;
    }

    public function str_replace($search, $replace, $string = null)
    {
        if (null !== $string) {
            $this->string = $string;
        }
        $this->string = str_replace($search, $replace, $this->string);
        return $this;
    }
}

Looks pretty silly to me though.

You might be able to incorporate a magic __call method but it's going to be a major pain to deal with the stored variable and optional method arguments.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜