análisis dynamic de tokens

Tengo un script de correo que uso en uno de mis proyectos, y me gustaría permitir la personalización de esta carta. el problema es que partes del correo electrónico se generan dinámicamente desde la base de datos. Tengo tokens predefinidos que uso para describir qué debería reemplazar el token, pero me gustaría simplificar esto pero escribir un analizador mejor que pueda interpretar el token y descubrir qué variable usar para reemplazarlo.

Ahora mismo tengo una matriz muy grande con todos los tokens posibles y sus valores correspondientes, así:

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

y luego corro a través de la plantilla y reemplazo cualquier instancia de la clave con su valor.

Prefiero simplemente ejecutar la plantilla, buscar [] o lo que sea que use para definir un token, y luego leer lo que hay dentro y convertirlo a un nombre de variable.

Necesito poder hacer coincidir algunos niveles de relaciones así que $this->account->owner->name; como ejemplo, y necesito poder hacer referencia a los métodos. $this->account->calcTotal();

Pensé que podría tomar el ejemplo [property_name] y reemplazar la instancia de _ con -> y luego llamar eso como una variable, pero no creo que funcione con los métodos.

Estás creando una especie de sistema de plantillas. Puedes reinventar la rueda (más o menos) codificando esto por tu cuenta o simplemente usando un sistema de plantilla lighweight como bigote .

Para un enfoque muy ligero puede hacer uso de expresiones regulares para formular la syntax de las variables de su plantilla. Simplemente defina cómo se puede escribir una variable, luego extraiga los nombres / tags utilizados y reemplácelos a voluntad.

Una función para usar para esto es preg_replace_callback . Aquí hay un pequeño código de ejemplo ( Demo ) que solo refleja la sustitución simple, sin embargo, puede modificar la rutina de reemplazo para acceder a los valores que necesita (en este ejemplo, estoy usando una variable que es una Array o implementa ArrayAccess ):

 template = $template; $this->vars = $vars; } public function replace(array $matches) { list(, $var) = $matches; if (isset($this->vars[$var])) { return $this->vars[$var]; } return sprintf('<>', $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(); 

Esto no se ve espectacular hasta ahora, solo está sustituyendo las tags de la plantilla por un valor. Sin embargo, como ya se mencionó, ahora puede inyectar una resolución en la plantilla que puede resolver las tags de plantilla a un valor en lugar de usar una matriz simple.

Ha indicado en su pregunta que le gustaría usar el símbolo _ para separarlo de los miembros / funciones del objeto. La siguiente es una clase de resolución que resolverá todas las variables globales a esa notación. Muestra cómo manejar tanto los miembros del objeto como los métodos y cómo recorrer las variables. Sin embargo, no se resuelve en $this sino en el espacio de nombres global:

 /** * 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.'); } } 

Esta clase de resolución se puede usar para usar algunos valores de ejemplo:

 /** * 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 = <<substituteVars(); 

Vea la demostración completa en acción .

Esto solo necesitará una pequeña modificación para satisfacer sus necesidades, finalmente.

PHP ya es un excelente sistema de plantillas por sí mismo.

Utilizo una clase de Plantilla simple, que acepta variables (a través de __set ()) y luego, cuando es hora de renderizar, solo hago un extracto () en la matriz de variables, e incluyo el archivo de plantilla.

Obviamente, esto se puede combinar con el almacenamiento en búfer de salida si necesita capturar el resultado en una cadena en lugar de enviar el resultado directamente al navegador / shell.

Esto le da la capacidad de tener plantillas muy simples, pero también le da funcionalidad avanzada si la necesita (es decir, para bucles, usando clases de ayuda, etc.)

He usado algo similar para plantillas de correo electrónico:

 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,  field; ?>