динамический анализ токенов

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

Прямо сейчас у меня есть очень большой массив со всеми возможными токенами и их соответствующими значениями, например:

$tokens['[property_name]'] = $this->name; 

и затем я просматриваю шаблон и заменяю любой экземпляр ключа его значением.

Я бы предпочел просто запустить шаблон, искать [] или все, что я использую для определения токена, а затем прочитать, что внутри, и преобразовать его в имя переменной.

Мне нужно уметь сопоставлять несколько уровней отношений, поэтому $this->account->owner->name; в качестве примера, и мне нужно иметь возможность ссылаться на методы. $this->account->calcTotal();$this->account->calcTotal();

Я подумал, что могу взять пример [property_name] и заменить экземпляр _ на -> а затем вызвать его как переменную, но я не думаю, что он работает с методами.

Related of "динамический анализ токенов"

Вы создаете систему шаблонов. Вы можете либо изобретать колесо (вроде), кодируя это самостоятельно, либо просто используя систему весовых шаблонов, такую ​​как усы .

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

Для этого используется функция preg_replace_callback . Вот пример небольшого примера ( Demo ), который отражает только простую подстановку, однако вы можете изменить процедуру замены для доступа к необходимым вам значениям (в этом примере я использую переменную, которая является либо Array либо реализует ArrayAccess ):

 <?php $template = <<<EOD This is my template, I can use [vars] at free [will]. EOD; class Template { private $template; private $vars; public function __construct($template, $vars) { $this->template = $template; $this->vars = $vars; } public function replace(array $matches) { list(, $var) = $matches; if (isset($this->vars[$var])) { return $this->vars[$var]; } return sprintf('<<undefined:%s>>', $var); } public function substituteVars() { $pattern = '~\[([a-z_]{3,})\]~'; $callback = array($this, 'replace'); return preg_replace_callback($pattern, $callback, $this->template ); } } $templ = new Template($template, array('vars' => 'variables')); echo $templ->substituteVars(); 

Пока это не выглядит эффектно, это просто заменяет теги шаблона на значение. Однако, как уже упоминалось, теперь вы можете ввести преобразователь в шаблон, который может разрешать теги шаблонов для значения вместо использования простого массива.

Вы указали в своем вопросе, что хотите использовать символ _ для отделения от элементов / функций объекта. Ниже приведен класс resolver, который будет разрешать все глобальные переменные для этой нотации. В нем показано, как обрабатывать как элементы, так и методы и методы перемещения переменных. Однако он не разрешает $this а глобальное пространство имен:

 /** * Resolve template variables from the global namespace */ class GlobalResolver implements ArrayAccess { private function resolve($offset) { $stack = explode('_', $offset); return $this->resolveOn($stack, $GLOBALS); } private function resolveOn($stack, $base) { $c = count($stack); if (!$c) return array(false, NULL); $var = array_shift($stack); $varIsset = isset($base[$var]); # non-set variables don't count if (!$varIsset) { return array($varIsset, NULL); } # simple variable if (1 === $c) { return array($varIsset, $base[$var]); } # descendant $operator = $stack[0]; $subject = $base[$var]; $desc = $this->resolvePair($subject, $operator); if (2 === $c || !$desc[0]) return $desc; $base = array($operator => $desc[1]); return $this->resolveOn($stack, $base); } private function resolvePair($subject, $operator) { if (is_object($subject)) { if (property_exists($subject, $operator)) { return array(true, $subject->$operator); } if (method_exists($subject, $operator)) { return array(true, $subject->$operator()); } } if (is_array($subject)) { if (array_key_exists($operator, $subject)) { return array(true, $subject[$operator]); } } return array(false, NULL); } public function offsetExists($offset) { list($isset) = $this->resolve($offset); return $isset; } public function offsetGet($offset) { list($isset, $value) = $this->resolve($offset); return $value; } public function offsetSet ($offset, $value) { throw new BadMethodCallException('Read only.'); } public function offsetUnset($offset) { throw new BadMethodCallException('Read only.'); } } 

Этот класс резольвера можно использовать тогда, чтобы использовать некоторые примерные значения:

 /** * fill the global namespace with some classes and variables */ class Foo { public $member = 'object member'; public function func() { return 'function result'; } public function child() { $child->member = 'child member'; return $child; } } $vars = 'variables'; $foo = new Foo; $template = <<<EOD This is my template, I can use [vars] at free [foo_func] or [foo_member] and even [foo_child_member]. EOD; /** * this time use the template with it's own resolver class */ $templ = new Template($template, new GlobalResolver); echo $templ->substituteVars(); 

Посмотрите полное демо в действии .

Это потребует незначительной модификации, чтобы в конечном итоге удовлетворить ваши потребности.

PHP уже является отличной системой шаблонов для своих собственных.

Я использую простой класс Template, который принимает переменные (через __set ()), а затем, когда пришло время рендеринга, просто сделайте extract () в массиве переменных и включите файл шаблона.

Это, очевидно, можно комбинировать с выходной буферизацией, если вам нужно записать результат в строку, а не отправлять результат прямо в браузер / оболочку.

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

Я использовал что-то подобное для шаблонов электронной почты:

 function call_php_with_vars( $_t_filename, $_t_variables ){ extract( $_t_variables ); ob_start(); include $_t_filename; $_t_result = ob_get_contents(); ob_end_clean(); return $_t_result; } echo call_php_with_vars('email_template.php',array( 'name'=>'Little Friend' ,'object'=>(object)array( 'field'=>'value' ) )); 

email_template.php:

 Hello, <?php echo $name; ?> <?php echo $object->field; ?>