Глобальные функции PHP, соединенные через класс - PullRequest
3 голосов
/ 11 мая 2011

Возможно ли связать все функции PHP через объект / класс?

У меня есть это в голове, и я представляю это примерно так:

$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 */);

это должно привести к:

Backoverflow

Спасибо.

Ответы [ 3 ]

6 голосов
/ 11 мая 2011

Посмотрите на:

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

особенно:

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

и возможно:

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

Поскольку многие опубликовали свои примеры, я тоже попробую:

<?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
4 голосов
/ 11 мая 2011

Вы хотите сделать str_replace('St', 'B', ucwords(strtolower('StackOverFlow')))?

Методы, которые вы вызываете выше, являются функциями, а не методами, привязанными к какому-либо классу. Chainer должен был бы реализовать эти методы. Если это то, что вы хотите сделать (возможно, для другой цели, и это только пример), ваша реализация Chainer может выглядеть так:

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;
   }
}

Это бы сработало в вашем примере выше, но вы бы назвали это так:

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

Обратите внимание, что вы никогда не получите значение /* the value from the first function argument */ из цепочки, так как это не имеет смысла. Возможно, вы могли бы сделать это с помощью глобальной переменной, но это было бы довольно отвратительно.

Дело в том, что вы можете объединять методы, возвращая $this каждый раз. Следующий метод вызывается для возвращенного значения, которое является тем же объектом, потому что вы его вернули (вернул $this). Важно знать, какие методы запускают и останавливают цепочку.

Я думаю, что эта реализация наиболее целесообразна:

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();
}
2 голосов
/ 11 мая 2011

Вы можете сделать это при условии, что класс Chainer выглядит примерно так:

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;
    }
}

Для меня это выглядит довольно глупо.

Возможно, вам удастся включить магический метод __call, но с сохраненной переменной и необязательными аргументами метода будет большая проблема.

...