Есть ли способ создать php-класс (или функцию), который «упрощает» это
ucfirst(str_replace('_',' ',html_entity_decode(trim($variable), ENT_QUOTES))));
Переменная $ может «прибывать» из любого места, например глобальная из другой функции или только «стандартная» переменная
Если вы используете его более одного раза, я бы определенно включил его в функцию. Таким образом, вы не будете повторять весь код.
function functionName($input){ return ucfirst(str_replace('_',' ',html_entity_decode(trim($input), ENT_QUOTES))); } echo functionName($variable);
Если вы хотите иметь это в классе (как следует из названия вопроса), вам следует создать классы фильтров. Это обычная вещь. Однако, по сравнению с простым вложением функций, это будет гораздо больше кода, чтобы сделать это правильно. Преимущество заключается в том, что вы можете легко расширять и комбинировать фильтры практически с любыми вашими фильтрационными потребностями.
Я быстро что-то взбесил.
interface IFilter { /** * @param Mixed $value The value to be filtered * @return Mixed The filtered value */ public function filter($value); }
Все фильтры должны реализовывать интерфейс IFilter
. Это делается для того, чтобы убедиться, что всякий раз, когда вы используете фильтр, у него есть метод filter()
который принимает один аргумент $value
. Мы не можем принудительно вводить возвращаемые значения, но блок doc указал, что мы ожидаем, что он вернет отфильтрованное значение. Два очень простых фильтра выглядят так:
class ucFirstFilter implements IFilter { public function filter($value) { return ucfirst($value); } } class TrimFilter implements IFilter { public function filter($value) { return trim($value); } }
Это не что иное, как обертка объектов вокруг двух собственных функций PHP. Вы используете его следующим образом:
$trimFilter = new TrimFilter; echo trimFilter->filter(' trim me '); // returns 'trim me'
Два других фильтра несколько сложнее, потому что они могут быть переданы более чем одним аргументом:
class SeparatorToSeparatorFilter implements IFilter { protected $_separator; protected $_replacement; public function __construct($separator = '_', $replacement = ' ') { $this->_separator = $separator; $this->_replacement = $replacement; } public function filter($value) { return str_replace($this->_separator, $this->_replacement, $value); } } class HtmlEntityDecodeFilter implements IFilter { protected $_quoteStyle; protected $_charset; public function __construct($quoteStyle=ENT_COMPAT, $charset='ISO-8859-1') { $this->_quoteStyle = $quoteStyle; $this->_charset = $charset; } public function filter($value) { return html_entity_decode($value, $this->_quoteStyle, $this->_charset); } }
Как вы можете видеть, конфигурация дополнительных аргументов выполняется через конструктор. Я использовал некоторые значения по умолчанию, поэтому вам нужно только их предоставить, когда вам нужно отклоняться от них. В случае второго фильтра я использовал настройки по умолчанию для собственной функции. Вот как вы их используете:
$trimFilter = new TrimFilter; $separatorFilter = new SeparatorToSeparatorFilter('-'); echo $separatorFilter->filter($trimFilter->filter(' trim-me ')); // returns 'trim me';
Теперь у вас может возникнуть соблазн добавить несколько фильтров в один класс фильтра. Dont. Каждый фильтр должен делать только одну вещь. Существует лучший способ объединения фильтров. Все, что вам нужно, это фильтр, который объединяет несколько других фильтров, например FilterChain:
class FilterChain implements IFilter { protected $_filters; public function __construct() { $this->_filters = new SplObjectStorage; } public function chain(IFilter $filter) { $this->_filters->attach($filter); return $this; } public function remove(IFilter $filter) { $this->_filters->detach($filter); return $this; } public function filter($value) { foreach($this->_filters as $filter) { $value = $filter->filter($value); } return $value; } }
FilterChain
принимает любой объект, который реализует IFilter
и если вы вызываете его методом filter()
, он будет перебирать все связанные фильтры в порядке, в котором вы его chain()
и возвращаете переданное $value
:
$filterChain = new FilterChain; $filterChain->chain(new ucFirstFilter) ->chain(new SeparatorToSeparatorFilter) ->chain(new HtmlEntityDecodeFilter(ENT_QUOTES, 'UTF-8')) ->chain(new TrimFilter); echo $filterChain->filter(' i am a "string_to_be_filtered" '); // outputs 'i am a "string to be filtered"'
Поскольку FilterChain
также реализует сам IFilter
, вы также можете добавить его в другие FilterChains. Это композитный шаблон . Фильтр, указанный выше, можно записать в виде
$chain1 = new FilterChain; $chain1->chain(new ucFirstFilter) ->chain(new SeparatorToSeparatorFilter); $chain2 = new FilterChain; $chain2->chain($chain1); $chain2->chain(new HtmlEntityDecodeFilter(ENT_QUOTES, 'UTF-8')) ->chain(new TrimFilter);
Как вы можете видеть, это гораздо больше кода, но он также очень расширяем. Главное преимущество перед тем, чтобы иметь одну функцию, которая обертывает все собственные функции в одну функцию, – вы можете комбинировать все, что угодно. Если вы решили, что вам нужна другая функция, которая не использует функцию trim()
, вам придется написать совершенно новую функцию, и вы случайно окажетесь с множеством функций и избыточным кодом для любой возможной комбинации фильтров. С FilterChain
вы просто добавляете фильтры и фильтры. А поскольку FilterChain
является объектом, вы можете свободно его передавать.
К счастью, такие библиотеки фильтров уже существуют, например, Zend_Filter предлагает ряд готовых фильтров и может использоваться автономно (например, без необходимости переноса вашего приложения на ZF).