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.
精彩评论