mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Fix #41, optimize variable parser
This commit is contained in:
parent
ae34025ca7
commit
982b284f60
@ -1,3 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once __DIR__.'/../../vendor/autoload.php';
|
require_once __DIR__.'/../../vendor/autoload.php';
|
||||||
|
|
||||||
|
$t = new Fenom\Tokenizer('some "asd {$$ddd} dfg" some');
|
||||||
|
|
||||||
|
var_dump($t->tokens);
|
@ -27,6 +27,7 @@ class Fenom
|
|||||||
const MODIFIER = 5;
|
const MODIFIER = 5;
|
||||||
|
|
||||||
/* Options */
|
/* Options */
|
||||||
|
const DENY_ACCESSOR = 0x8;
|
||||||
const DENY_METHODS = 0x10;
|
const DENY_METHODS = 0x10;
|
||||||
const DENY_NATIVE_FUNCS = 0x20;
|
const DENY_NATIVE_FUNCS = 0x20;
|
||||||
const FORCE_INCLUDE = 0x40;
|
const FORCE_INCLUDE = 0x40;
|
||||||
@ -55,6 +56,7 @@ class Fenom
|
|||||||
* @see setOptions
|
* @see setOptions
|
||||||
*/
|
*/
|
||||||
private static $_options_list = array(
|
private static $_options_list = array(
|
||||||
|
"disable_accessor" => self::DENY_ACCESSOR,
|
||||||
"disable_methods" => self::DENY_METHODS,
|
"disable_methods" => self::DENY_METHODS,
|
||||||
"disable_native_funcs" => self::DENY_NATIVE_FUNCS,
|
"disable_native_funcs" => self::DENY_NATIVE_FUNCS,
|
||||||
"disable_cache" => self::DISABLE_CACHE,
|
"disable_cache" => self::DISABLE_CACHE,
|
||||||
@ -129,7 +131,7 @@ class Fenom
|
|||||||
* @var array of allowed PHP functions
|
* @var array of allowed PHP functions
|
||||||
*/
|
*/
|
||||||
protected $_allowed_funcs = array(
|
protected $_allowed_funcs = array(
|
||||||
"count" => 1, "is_string" => 1, "is_array" => 1, "is_numeric" => 1, "is_int" => 1,
|
"count" => 1, "is_string" => 1, "is_array" => 1, "is_numeric" => 1, "is_int" => 1, 'constant' => 1,
|
||||||
"is_object" => 1, "strtotime" => 1, "gettype" => 1, "is_double" => 1, "json_encode" => 1, "json_decode" => 1,
|
"is_object" => 1, "strtotime" => 1, "gettype" => 1, "is_double" => 1, "json_encode" => 1, "json_decode" => 1,
|
||||||
"ip2long" => 1, "long2ip" => 1, "strip_tags" => 1, "nl2br" => 1, "explode" => 1, "implode" => 1
|
"ip2long" => 1, "long2ip" => 1, "strip_tags" => 1, "nl2br" => 1, "explode" => 1, "implode" => 1
|
||||||
);
|
);
|
||||||
|
@ -74,7 +74,7 @@ class Compiler
|
|||||||
public static function ifOpen(Tokenizer $tokens, Scope $scope)
|
public static function ifOpen(Tokenizer $tokens, Scope $scope)
|
||||||
{
|
{
|
||||||
$scope["else"] = false;
|
$scope["else"] = false;
|
||||||
return 'if(' . $scope->tpl->parseExp($tokens, true) . ') {';
|
return 'if(' . $scope->tpl->parseExpr($tokens) . ') {';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,7 +91,7 @@ class Compiler
|
|||||||
if ($scope["else"]) {
|
if ($scope["else"]) {
|
||||||
throw new InvalidUsageException('Incorrect use of the tag {elseif}');
|
throw new InvalidUsageException('Incorrect use of the tag {elseif}');
|
||||||
}
|
}
|
||||||
return '} elseif(' . $scope->tpl->parseExp($tokens, true) . ') {';
|
return '} elseif(' . $scope->tpl->parseExpr($tokens) . ') {';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,11 +137,11 @@ class Compiler
|
|||||||
}
|
}
|
||||||
$tokens->get(T_AS);
|
$tokens->get(T_AS);
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$value = $scope->tpl->parseVariable($tokens, Template::DENY_MODS | Template::DENY_ARRAY);
|
$value = $scope->tpl->parseVar($tokens);
|
||||||
if ($tokens->is(T_DOUBLE_ARROW)) {
|
if ($tokens->is(T_DOUBLE_ARROW)) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$key = $value;
|
$key = $value;
|
||||||
$value = $scope->tpl->parseVariable($tokens, Template::DENY_MODS | Template::DENY_ARRAY);
|
$value = $scope->tpl->parseVar($tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope["after"] = array();
|
$scope["after"] = array();
|
||||||
@ -154,7 +154,7 @@ class Compiler
|
|||||||
}
|
}
|
||||||
$tokens->getNext("=");
|
$tokens->getNext("=");
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$p[$param] = $scope->tpl->parseVariable($tokens, Template::DENY_MODS | Template::DENY_ARRAY);
|
$p[$param] = $scope->tpl->parseVar($tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($p["index"]) {
|
if ($p["index"]) {
|
||||||
@ -228,7 +228,7 @@ class Compiler
|
|||||||
$var = $scope->tpl->parseVariable($tokens, Template::DENY_MODS);
|
$var = $scope->tpl->parseVariable($tokens, Template::DENY_MODS);
|
||||||
$tokens->get("=");
|
$tokens->get("=");
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$val = $scope->tpl->parseExp($tokens, true);
|
$val = $scope->tpl->parseExpr($tokens);
|
||||||
$p = $scope->tpl->parseParams($tokens, $p);
|
$p = $scope->tpl->parseParams($tokens, $p);
|
||||||
|
|
||||||
if (is_numeric($p["step"])) {
|
if (is_numeric($p["step"])) {
|
||||||
@ -305,7 +305,7 @@ class Compiler
|
|||||||
*/
|
*/
|
||||||
public static function whileOpen(Tokenizer $tokens, Scope $scope)
|
public static function whileOpen(Tokenizer $tokens, Scope $scope)
|
||||||
{
|
{
|
||||||
return 'while(' . $scope->tpl->parseExp($tokens, true) . ') {';
|
return 'while(' . $scope->tpl->parseExpr($tokens) . ') {';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -319,7 +319,7 @@ class Compiler
|
|||||||
public static function switchOpen(Tokenizer $tokens, Scope $scope)
|
public static function switchOpen(Tokenizer $tokens, Scope $scope)
|
||||||
{
|
{
|
||||||
$scope["no-break"] = $scope["no-continue"] = true;
|
$scope["no-break"] = $scope["no-continue"] = true;
|
||||||
$scope["switch"] = 'switch(' . $scope->tpl->parseExp($tokens, true) . ') {';
|
$scope["switch"] = 'switch(' . $scope->tpl->parseExpr($tokens) . ') {';
|
||||||
// lazy init
|
// lazy init
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@ -334,7 +334,7 @@ class Compiler
|
|||||||
*/
|
*/
|
||||||
public static function tagCase(Tokenizer $tokens, Scope $scope)
|
public static function tagCase(Tokenizer $tokens, Scope $scope)
|
||||||
{
|
{
|
||||||
$code = 'case ' . $scope->tpl->parseExp($tokens, true) . ': ';
|
$code = 'case ' . $scope->tpl->parseExpr($tokens) . ': ';
|
||||||
if ($scope["switch"]) {
|
if ($scope["switch"]) {
|
||||||
unset($scope["no-break"], $scope["no-continue"]);
|
unset($scope["no-break"], $scope["no-continue"]);
|
||||||
$code = $scope["switch"] . "\n" . $code;
|
$code = $scope["switch"] . "\n" . $code;
|
||||||
@ -713,7 +713,7 @@ class Compiler
|
|||||||
if ($tokens->is("[")) {
|
if ($tokens->is("[")) {
|
||||||
return $var . '=' . $scope->tpl->parseArray($tokens);
|
return $var . '=' . $scope->tpl->parseArray($tokens);
|
||||||
} else {
|
} else {
|
||||||
return $var . '=' . $scope->tpl->parseExp($tokens, true);
|
return $var . '=' . $scope->tpl->parseExpr($tokens);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$scope["name"] = $var;
|
$scope["name"] = $var;
|
||||||
@ -771,7 +771,7 @@ class Compiler
|
|||||||
if ($tokens->is("[")) {
|
if ($tokens->is("[")) {
|
||||||
$exp = $tpl->parseArray($tokens);
|
$exp = $tpl->parseArray($tokens);
|
||||||
} else {
|
} else {
|
||||||
$exp = $tpl->parseExp($tokens, true);
|
$exp = $tpl->parseExpr($tokens);
|
||||||
}
|
}
|
||||||
if ($tokens->valid()) {
|
if ($tokens->valid()) {
|
||||||
$p = $tpl->parseParams($tokens);
|
$p = $tpl->parseParams($tokens);
|
||||||
@ -944,7 +944,7 @@ class Compiler
|
|||||||
throw new InvalidUsageException("Raw mode allow for expressions or functions");
|
throw new InvalidUsageException("Raw mode allow for expressions or functions");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$code = $tpl->out($tpl->parseExp($tokens, true));
|
$code = $tpl->out($tpl->parseExpr($tokens));
|
||||||
}
|
}
|
||||||
$tpl->escape = $escape;
|
$tpl->escape = $escape;
|
||||||
return $code;
|
return $code;
|
||||||
|
@ -190,7 +190,8 @@ class Render extends \ArrayObject
|
|||||||
* @param $name
|
* @param $name
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getMacro($name) {
|
public function getMacro($name)
|
||||||
|
{
|
||||||
return $this->_macros[$name];
|
return $this->_macros[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,14 +398,14 @@ class Template extends Render
|
|||||||
public function getTemplateCode()
|
public function getTemplateCode()
|
||||||
{
|
{
|
||||||
|
|
||||||
if($this->macros) {
|
if ($this->macros) {
|
||||||
$macros = array();
|
$macros = array();
|
||||||
foreach($this->macros as $m) {
|
foreach ($this->macros as $m) {
|
||||||
if($m["recursive"]) {
|
if ($m["recursive"]) {
|
||||||
$macros[] = "\t\t'".$m["name"]."' => function (\$tpl) {\n?>".$m["body"]."<?php\n}";
|
$macros[] = "\t\t'" . $m["name"] . "' => function (\$tpl) {\n?>" . $m["body"] . "<?php\n}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$macros = "\n".implode(",\n", $macros);
|
$macros = "\n" . implode(",\n", $macros);
|
||||||
} else {
|
} else {
|
||||||
$macros = "";
|
$macros = "";
|
||||||
}
|
}
|
||||||
@ -413,14 +413,14 @@ class Template extends Render
|
|||||||
return "<?php \n" .
|
return "<?php \n" .
|
||||||
"/** Fenom template '" . $this->_name . "' compiled at " . date('Y-m-d H:i:s') . " */\n" .
|
"/** Fenom template '" . $this->_name . "' compiled at " . date('Y-m-d H:i:s') . " */\n" .
|
||||||
$before . // some code 'before' template
|
$before . // some code 'before' template
|
||||||
"return new Fenom\\Render(\$fenom, " . $this->_getClosureSource() . ", array(\n".
|
"return new Fenom\\Render(\$fenom, " . $this->_getClosureSource() . ", array(\n" .
|
||||||
"\t'options' => {$this->_options},\n".
|
"\t'options' => {$this->_options},\n" .
|
||||||
"\t'provider' => ".var_export($this->_scm, true).",\n".
|
"\t'provider' => " . var_export($this->_scm, true) . ",\n" .
|
||||||
"\t'name' => ".var_export($this->_name, true).",\n".
|
"\t'name' => " . var_export($this->_name, true) . ",\n" .
|
||||||
"\t'base_name' => ".var_export($this->_base_name, true).",\n".
|
"\t'base_name' => " . var_export($this->_base_name, true) . ",\n" .
|
||||||
"\t'time' => {$this->_time},\n".
|
"\t'time' => {$this->_time},\n" .
|
||||||
"\t'depends' => ".var_export($this->_base_name, true).",\n".
|
"\t'depends' => " . var_export($this->_base_name, true) . ",\n" .
|
||||||
"\t'macros' => array({$macros}),
|
"\t'macros' => array({$macros}),
|
||||||
));\n";
|
));\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,10 +498,8 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
} elseif ($tokens->is('/')) {
|
} elseif ($tokens->is('/')) {
|
||||||
return $this->parseEndTag($tokens);
|
return $this->parseEndTag($tokens);
|
||||||
} elseif ($tokens->is('#')) {
|
|
||||||
return $this->out($this->parseConst($tokens), $tokens);
|
|
||||||
} else {
|
} else {
|
||||||
return $this->out($this->parseExp($tokens), $tokens);
|
return $this->out($this->parseExpr($tokens), $tokens);
|
||||||
}
|
}
|
||||||
} catch (InvalidUsageException $e) {
|
} catch (InvalidUsageException $e) {
|
||||||
throw new CompileException($e->getMessage() . " in {$this} line {$this->_line}", 0, E_ERROR, $this->_name, $this->_line, $e);
|
throw new CompileException($e->getMessage() . " in {$this} line {$this->_line}", 0, E_ERROR, $this->_name, $this->_line, $e);
|
||||||
@ -563,11 +561,11 @@ class Template extends Render
|
|||||||
if ($tokens->is(Tokenizer::MACRO_STRING)) {
|
if ($tokens->is(Tokenizer::MACRO_STRING)) {
|
||||||
$action = $tokens->getAndNext();
|
$action = $tokens->getAndNext();
|
||||||
} else {
|
} else {
|
||||||
return $this->out($this->parseExp($tokens)); // may be math and/or boolean expression
|
return $this->out($this->parseExpr($tokens)); // may be math and/or boolean expression
|
||||||
}
|
}
|
||||||
if ($tokens->is("(", T_NAMESPACE, T_DOUBLE_COLON) && !$tokens->isWhiteSpaced()) { // just invoke function or static method
|
if ($tokens->is("(", T_NAMESPACE, T_DOUBLE_COLON) && !$tokens->isWhiteSpaced()) { // just invoke function or static method
|
||||||
$tokens->back();
|
$tokens->back();
|
||||||
return $this->out($this->parseExp($tokens));
|
return $this->out($this->parseExpr($tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($tokens->is('.')) {
|
if ($tokens->is('.')) {
|
||||||
@ -616,14 +614,13 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse expressions. The mix of operations and terms.
|
* Parse expressions. The mix of operators and terms.
|
||||||
*
|
*
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param bool $required
|
|
||||||
* @return string
|
* @return string
|
||||||
* @throws Error\UnexpectedTokenException
|
* @throws Error\UnexpectedTokenException
|
||||||
*/
|
*/
|
||||||
public function parseExp(Tokenizer $tokens, $required = false)
|
public function parseExpr(Tokenizer $tokens)
|
||||||
{
|
{
|
||||||
$exp = array();
|
$exp = array();
|
||||||
$var = false; // last term was: true - variable, false - mixed
|
$var = false; // last term was: true - variable, false - mixed
|
||||||
@ -673,15 +670,15 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
} elseif ($tokens->is('~')) { // string concatenation operator: 'asd' ~ $var
|
} elseif ($tokens->is('~')) { // string concatenation operator: 'asd' ~ $var
|
||||||
$concat = array(array_pop($exp));
|
$concat = array(array_pop($exp));
|
||||||
while($tokens->is('~')) {
|
while ($tokens->is('~')) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
if($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
if ($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
||||||
$concat[] = "strval(".$this->parseTerm($tokens).")";
|
$concat[] = "strval(" . $this->parseTerm($tokens) . ")";
|
||||||
} else {
|
} else {
|
||||||
$concat[] = $this->parseTerm($tokens);
|
$concat[] = $this->parseTerm($tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$exp[] = "(".implode(".", $concat).")";
|
$exp[] = "(" . implode(".", $concat) . ")";
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -690,17 +687,14 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($op) {
|
if ($op || !$exp) {
|
||||||
throw new UnexpectedTokenException($tokens);
|
|
||||||
}
|
|
||||||
if ($required && !$exp) {
|
|
||||||
throw new UnexpectedTokenException($tokens);
|
throw new UnexpectedTokenException($tokens);
|
||||||
}
|
}
|
||||||
return implode(' ', $exp);
|
return implode(' ', $exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse any term: -2, ++$var, 'adf'|mod:4
|
* Parse any term of expression: -2, ++$var, 'adf'|mod:4
|
||||||
*
|
*
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param bool $is_var
|
* @param bool $is_var
|
||||||
@ -712,132 +706,98 @@ class Template extends Render
|
|||||||
public function parseTerm(Tokenizer $tokens, &$is_var = false)
|
public function parseTerm(Tokenizer $tokens, &$is_var = false)
|
||||||
{
|
{
|
||||||
$is_var = false;
|
$is_var = false;
|
||||||
$unary = "";
|
if ($tokens->is(Tokenizer::MACRO_UNARY)) {
|
||||||
term: {
|
$unary = $tokens->getAndNext();
|
||||||
if ($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
} else {
|
||||||
return $unary . $this->parseScalar($tokens, true);
|
$unary = "";
|
||||||
} elseif ($tokens->is(T_CONSTANT_ENCAPSED_STRING, '"', T_ENCAPSED_AND_WHITESPACE)) {
|
}
|
||||||
if ($unary) {
|
if ($tokens->is(T_LNUMBER, T_DNUMBER)) {
|
||||||
throw new UnexpectedTokenException($tokens->back());
|
return $unary . $this->parseScalar($tokens, true);
|
||||||
}
|
} elseif ($tokens->is(T_CONSTANT_ENCAPSED_STRING, '"', T_ENCAPSED_AND_WHITESPACE)) {
|
||||||
return $this->parseScalar($tokens, true);
|
if ($unary) {
|
||||||
} elseif ($tokens->is(T_VARIABLE)) {
|
throw new UnexpectedTokenException($tokens->back());
|
||||||
$var = $this->parseVar($tokens);
|
}
|
||||||
if ($tokens->is(Tokenizer::MACRO_INCDEC, "|", "!", "?")) {
|
return $this->parseScalar($tokens, true);
|
||||||
return $unary . $this->parseVariable($tokens, 0, $var);
|
} elseif ($tokens->is(T_VARIABLE)) {
|
||||||
} elseif ($tokens->is("(") && $tokens->hasBackList(T_STRING)) { // method call
|
$var = $this->parseVar($tokens);
|
||||||
return $unary . $this->parseVariable($tokens, 0, $var);
|
if ($tokens->is(Tokenizer::MACRO_INCDEC, "|", "!", "?")) {
|
||||||
} elseif ($unary) {
|
return $unary . $this->parseVariable($tokens, 0, $var);
|
||||||
return $unary . $var;
|
} elseif ($tokens->is("(") && $tokens->hasBackList(T_STRING)) { // method call
|
||||||
} else {
|
return $unary . $this->parseVariable($tokens, 0, $var);
|
||||||
$is_var = true;
|
|
||||||
return $var;
|
|
||||||
}
|
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
|
||||||
return $unary . $this->parseVariable($tokens);
|
|
||||||
} elseif ($tokens->is("(")) {
|
|
||||||
$tokens->next();
|
|
||||||
$exp = $unary . "(" . $this->parseExp($tokens, true) . ")";
|
|
||||||
$tokens->need(")")->next();
|
|
||||||
return $exp;
|
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_UNARY)) {
|
|
||||||
if ($unary) {
|
|
||||||
throw new UnexpectedTokenException($tokens);
|
|
||||||
}
|
|
||||||
$unary = $tokens->getAndNext();
|
|
||||||
goto term;
|
|
||||||
} elseif ($tokens->is(T_STRING)) {
|
|
||||||
if ($tokens->isSpecialVal()) {
|
|
||||||
return $unary . $tokens->getAndNext();
|
|
||||||
} elseif ($tokens->isNext("(") && !$tokens->getWhitespace()) {
|
|
||||||
$func = $this->_fenom->getModifier($tokens->current(), $this);
|
|
||||||
if (!$func) {
|
|
||||||
throw new \Exception("Function " . $tokens->getAndNext() . " not found");
|
|
||||||
}
|
|
||||||
$tokens->next();
|
|
||||||
$func = $func . $this->parseArgs($tokens);
|
|
||||||
if ($tokens->is('|')) {
|
|
||||||
return $unary . $this->parseModifier($tokens, $func);
|
|
||||||
} else {
|
|
||||||
return $unary . $func;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} elseif ($tokens->is(T_ISSET, T_EMPTY)) {
|
|
||||||
$func = $tokens->getAndNext();
|
|
||||||
if ($tokens->is("(") && $tokens->isNext(T_VARIABLE)) {
|
|
||||||
$tokens->next();
|
|
||||||
$exp = $func . "(" . $this->parseVar($tokens) . ")";
|
|
||||||
$tokens->need(')')->next();
|
|
||||||
return $unary . $exp;
|
|
||||||
} else {
|
|
||||||
throw new TokenizeException("Unexpected token " . $tokens->getNext() . ", isset() and empty() accept only variables");
|
|
||||||
}
|
|
||||||
} elseif ($tokens->is('[')) {
|
|
||||||
if ($unary) {
|
|
||||||
throw new UnexpectedTokenException($tokens->back());
|
|
||||||
}
|
|
||||||
return $this->parseArray($tokens);
|
|
||||||
} elseif ($unary) {
|
} elseif ($unary) {
|
||||||
$tokens->back();
|
return $unary . $var;
|
||||||
throw new UnexpectedTokenException($tokens);
|
} else {
|
||||||
|
$is_var = true;
|
||||||
|
return $var;
|
||||||
|
}
|
||||||
|
} elseif ($tokens->is('$')) {
|
||||||
|
$var = $this->parseAccessor($tokens, $is_var);
|
||||||
|
if ($tokens->is(Tokenizer::MACRO_INCDEC, "|", "!", "?")) {
|
||||||
|
return $unary . $this->parseVariable($tokens, 0, $var);
|
||||||
|
} else {
|
||||||
|
return $unary . $var;
|
||||||
|
}
|
||||||
|
} elseif ($tokens->is(Tokenizer::MACRO_INCDEC)) {
|
||||||
|
return $unary . $this->parseVariable($tokens);
|
||||||
|
} elseif ($tokens->is("(")) {
|
||||||
|
$tokens->next();
|
||||||
|
$exp = $unary . "(" . $this->parseExpr($tokens) . ")";
|
||||||
|
$tokens->need(")")->next();
|
||||||
|
return $exp;
|
||||||
|
} elseif ($tokens->is(T_STRING)) {
|
||||||
|
if ($tokens->isSpecialVal()) {
|
||||||
|
return $unary . $tokens->getAndNext();
|
||||||
|
} elseif ($tokens->isNext("(") && !$tokens->getWhitespace()) {
|
||||||
|
$func = $this->_fenom->getModifier($tokens->current(), $this);
|
||||||
|
if (!$func) {
|
||||||
|
throw new \Exception("Function " . $tokens->getAndNext() . " not found");
|
||||||
|
}
|
||||||
|
$tokens->next();
|
||||||
|
$func = $func . $this->parseArgs($tokens);
|
||||||
|
if ($tokens->is('|')) {
|
||||||
|
return $unary . $this->parseModifier($tokens, $func);
|
||||||
|
} else {
|
||||||
|
return $unary . $func;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} elseif ($tokens->is(T_ISSET, T_EMPTY)) {
|
||||||
|
$func = $tokens->getAndNext();
|
||||||
|
if ($tokens->is("(") && $tokens->isNext(T_VARIABLE)) {
|
||||||
|
$tokens->next();
|
||||||
|
$exp = $func . "(" . $this->parseVar($tokens) . ")";
|
||||||
|
$tokens->need(')')->next();
|
||||||
|
return $unary . $exp;
|
||||||
|
} else {
|
||||||
|
throw new TokenizeException("Unexpected token " . $tokens->getNext() . ", isset() and empty() accept only variables");
|
||||||
|
}
|
||||||
|
} elseif ($tokens->is('[')) {
|
||||||
|
if ($unary) {
|
||||||
|
throw new UnexpectedTokenException($tokens->back());
|
||||||
|
}
|
||||||
|
return $this->parseArray($tokens);
|
||||||
|
} elseif ($unary) {
|
||||||
|
$tokens->back();
|
||||||
|
throw new UnexpectedTokenException($tokens);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse simple variable (without modifier etc)
|
* Parse simple variable (without modifier etc)
|
||||||
*
|
*
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @param int $options
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function parseVar(Tokenizer $tokens, $options = 0)
|
public function parseVar(Tokenizer $tokens)
|
||||||
{
|
{
|
||||||
$var = $tokens->get(T_VARIABLE);
|
$var = $tokens->get(T_VARIABLE);
|
||||||
$_var = '$tpl["' . substr($var, 1) . '"]';
|
$_var = '$tpl["' . substr($var, 1) . '"]';
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
while ($t = $tokens->key()) {
|
$_var = $this->_var($tokens, $_var);
|
||||||
if ($t === "." && !($options & self::DENY_ARRAY)) {
|
|
||||||
$key = $tokens->getNext();
|
|
||||||
if ($tokens->is(T_VARIABLE)) {
|
|
||||||
$key = "[ " . $this->parseVariable($tokens, self::DENY_ARRAY) . " ]";
|
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_STRING)) {
|
|
||||||
$key = '["' . $key . '"]';
|
|
||||||
$tokens->next();
|
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR, '"')) {
|
|
||||||
$key = "[" . $this->parseScalar($tokens, false) . "]";
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$_var .= $key;
|
|
||||||
} elseif ($t === "[" && !($options & self::DENY_ARRAY)) {
|
|
||||||
$tokens->next();
|
|
||||||
if ($tokens->is(Tokenizer::MACRO_STRING)) {
|
|
||||||
if ($tokens->isNext("(")) {
|
|
||||||
$key = "[" . $this->parseExp($tokens) . "]";
|
|
||||||
} else {
|
|
||||||
$key = '["' . $tokens->current() . '"]';
|
|
||||||
$tokens->next();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$key = "[" . $this->parseExp($tokens, true) . "]";
|
|
||||||
}
|
|
||||||
$tokens->get("]");
|
|
||||||
$tokens->next();
|
|
||||||
$_var .= $key;
|
|
||||||
} elseif ($t === T_DNUMBER) {
|
|
||||||
$_var .= '[' . substr($tokens->getAndNext(), 1) . ']';
|
|
||||||
} elseif ($t === T_OBJECT_OPERATOR) {
|
|
||||||
$_var .= "->" . $tokens->getNext(T_STRING);
|
|
||||||
$tokens->next();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($this->_options & Fenom::FORCE_VERIFY) {
|
if ($this->_options & Fenom::FORCE_VERIFY) {
|
||||||
return 'isset(' . $_var . ') ? ' . $_var . ' : null';
|
return 'isset(' . $_var . ') ? ' . $_var . ' : null';
|
||||||
} else {
|
} else {
|
||||||
@ -845,6 +805,56 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tokenizer $tokens
|
||||||
|
* @param $var
|
||||||
|
* @return string
|
||||||
|
* @throws Error\UnexpectedTokenException
|
||||||
|
*/
|
||||||
|
protected function _var(Tokenizer $tokens, $var)
|
||||||
|
{
|
||||||
|
while ($t = $tokens->key()) {
|
||||||
|
if ($t === ".") {
|
||||||
|
$tokens->next();
|
||||||
|
if ($tokens->is(T_VARIABLE)) {
|
||||||
|
$key = '[ $tpl["' . substr($tokens->getAndNext(), 1) . '"] ]';
|
||||||
|
} elseif ($tokens->is(Tokenizer::MACRO_STRING)) {
|
||||||
|
$key = '["' . $tokens->getAndNext() . '"]';
|
||||||
|
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR)) {
|
||||||
|
$key = "[" . $tokens->getAndNext() . "]";
|
||||||
|
} elseif ($tokens->is('"')) {
|
||||||
|
$key = "[" . $this->parseQuote($tokens) . "]";
|
||||||
|
} else {
|
||||||
|
throw new UnexpectedTokenException($tokens);
|
||||||
|
}
|
||||||
|
$var .= $key;
|
||||||
|
} elseif ($t === "[") {
|
||||||
|
$tokens->next();
|
||||||
|
if ($tokens->is(Tokenizer::MACRO_STRING)) {
|
||||||
|
if ($tokens->isNext("(")) {
|
||||||
|
$key = "[" . $this->parseExpr($tokens) . "]";
|
||||||
|
} else {
|
||||||
|
$key = '["' . $tokens->current() . '"]';
|
||||||
|
$tokens->next();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$key = "[" . $this->parseExpr($tokens) . "]";
|
||||||
|
}
|
||||||
|
$tokens->get("]");
|
||||||
|
$tokens->next();
|
||||||
|
$var .= $key;
|
||||||
|
} elseif ($t === T_DNUMBER) {
|
||||||
|
$var .= '[' . substr($tokens->getAndNext(), 1) . ']';
|
||||||
|
} elseif ($t === T_OBJECT_OPERATOR) {
|
||||||
|
$var .= "->" . $tokens->getNext(T_STRING);
|
||||||
|
$tokens->next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $var;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse complex variable
|
* Parse complex variable
|
||||||
* $var.foo[bar]["a"][1+3/$var]|mod:3:"w":$var3|mod3
|
* $var.foo[bar]["a"][1+3/$var]|mod:3:"w":$var3|mod3
|
||||||
@ -901,6 +911,60 @@ class Template extends Render
|
|||||||
return $var;
|
return $var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse accessor
|
||||||
|
*/
|
||||||
|
public function parseAccessor(Tokenizer $tokens, &$is_var)
|
||||||
|
{
|
||||||
|
$is_var = false;
|
||||||
|
$vars = array(
|
||||||
|
'get' => '$_GET',
|
||||||
|
'post' => '$_POST',
|
||||||
|
'session' => '$_SESSION',
|
||||||
|
'cookie' => '$_COOKIE',
|
||||||
|
'request' => '$_REQUEST',
|
||||||
|
'files' => '$_FILES',
|
||||||
|
'globals' => '$GLOBALS',
|
||||||
|
'server' => '$_SERVER',
|
||||||
|
'env' => '$_ENV',
|
||||||
|
);
|
||||||
|
if ($this->_options & Fenom::DENY_ACCESSOR) {
|
||||||
|
throw new \LogicException("Accessor are disabled");
|
||||||
|
}
|
||||||
|
$key = $tokens->need('$')->next()->need('.')->next()->current();
|
||||||
|
$tokens->next();
|
||||||
|
if (isset($vars[$key])) {
|
||||||
|
$is_var = true;
|
||||||
|
return $this->_var($tokens, $vars[$key]);
|
||||||
|
}
|
||||||
|
switch ($key) {
|
||||||
|
case 'const':
|
||||||
|
$tokens->need('.')->next();
|
||||||
|
$var = $this->parseName($tokens);
|
||||||
|
if (!defined($var)) {
|
||||||
|
$var = 'constant(' . var_export($var, true) . ')';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'version':
|
||||||
|
$var = '\Fenom::VERSION';
|
||||||
|
break;
|
||||||
|
case 'tpl':
|
||||||
|
$var = '$tpl->getName()';
|
||||||
|
break;
|
||||||
|
case 'schema':
|
||||||
|
$var = '$tpl->getScm()';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnexpectedTokenException($tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($tokens->is('|')) {
|
||||||
|
return $this->parseModifier($tokens, $var);
|
||||||
|
} else {
|
||||||
|
return $var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse ternary operator
|
* Parse ternary operator
|
||||||
*
|
*
|
||||||
@ -917,9 +981,9 @@ class Template extends Render
|
|||||||
if ($tokens->is(":")) {
|
if ($tokens->is(":")) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
if ($empty) {
|
if ($empty) {
|
||||||
return '(empty(' . $var . ') ? (' . $this->parseExp($tokens, true) . ') : ' . $var . ')';
|
return '(empty(' . $var . ') ? (' . $this->parseExpr($tokens) . ') : ' . $var . ')';
|
||||||
} else {
|
} else {
|
||||||
return '(isset(' . $var . ') ? ' . $var . ' : (' . $this->parseExp($tokens, true) . '))';
|
return '(isset(' . $var . ') ? ' . $var . ' : (' . $this->parseExpr($tokens) . '))';
|
||||||
}
|
}
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_BINARY, Tokenizer::MACRO_BOOLEAN, Tokenizer::MACRO_MATH) || !$tokens->valid()) {
|
} elseif ($tokens->is(Tokenizer::MACRO_BINARY, Tokenizer::MACRO_BOOLEAN, Tokenizer::MACRO_MATH) || !$tokens->valid()) {
|
||||||
if ($empty) {
|
if ($empty) {
|
||||||
@ -928,9 +992,9 @@ class Template extends Render
|
|||||||
return 'isset(' . $var . ')';
|
return 'isset(' . $var . ')';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$expr1 = $this->parseExp($tokens, true);
|
$expr1 = $this->parseExpr($tokens);
|
||||||
$tokens->need(':')->skip();
|
$tokens->need(':')->skip();
|
||||||
$expr2 = $this->parseExp($tokens, true);
|
$expr2 = $this->parseExpr($tokens);
|
||||||
if ($empty) {
|
if ($empty) {
|
||||||
return '(empty(' . $var . ') ? ' . $expr2 . ' : ' . $expr1 . ')';
|
return '(empty(' . $var . ') ? ' . $expr2 . ' : ' . $expr1 . ')';
|
||||||
} else {
|
} else {
|
||||||
@ -1133,7 +1197,7 @@ class Template extends Render
|
|||||||
$_str = "";
|
$_str = "";
|
||||||
}
|
}
|
||||||
$tokens->getNext(T_VARIABLE);
|
$tokens->getNext(T_VARIABLE);
|
||||||
$_str .= '(' . $this->parseExp($tokens) . ')';
|
$_str .= '(' . $this->parseExpr($tokens) . ')';
|
||||||
if ($tokens->is($stop)) {
|
if ($tokens->is($stop)) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
return $_str;
|
return $_str;
|
||||||
@ -1202,7 +1266,7 @@ class Template extends Render
|
|||||||
} elseif ($tokens->is('"', '`', T_ENCAPSED_AND_WHITESPACE)) {
|
} elseif ($tokens->is('"', '`', T_ENCAPSED_AND_WHITESPACE)) {
|
||||||
$args[] = $this->parseQuote($tokens);
|
$args[] = $this->parseQuote($tokens);
|
||||||
} elseif ($tokens->is('(')) {
|
} elseif ($tokens->is('(')) {
|
||||||
$args[] = $this->parseExp($tokens, true);
|
$args[] = $this->parseExpr($tokens);
|
||||||
} elseif ($tokens->is('[')) {
|
} elseif ($tokens->is('[')) {
|
||||||
$args[] = $this->parseArray($tokens);
|
$args[] = $this->parseArray($tokens);
|
||||||
} elseif ($tokens->is(T_STRING) && $tokens->isNext('(')) {
|
} elseif ($tokens->is(T_STRING) && $tokens->isNext('(')) {
|
||||||
@ -1246,7 +1310,7 @@ class Template extends Render
|
|||||||
$val = false;
|
$val = false;
|
||||||
$_arr .= $tokens->getAndNext() . ' ';
|
$_arr .= $tokens->getAndNext() . ' ';
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR, T_VARIABLE, T_STRING, T_EMPTY, T_ISSET, "(", "#") && !$val) {
|
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR, T_VARIABLE, T_STRING, T_EMPTY, T_ISSET, "(", "#") && !$val) {
|
||||||
$_arr .= $this->parseExp($tokens, true);
|
$_arr .= $this->parseExpr($tokens);
|
||||||
$key = false;
|
$key = false;
|
||||||
$val = true;
|
$val = true;
|
||||||
} elseif ($tokens->is('"') && !$val) {
|
} elseif ($tokens->is('"') && !$val) {
|
||||||
@ -1311,11 +1375,11 @@ class Template extends Render
|
|||||||
$n = $this->i++;
|
$n = $this->i++;
|
||||||
if ($recursive) {
|
if ($recursive) {
|
||||||
$recursive['recursive'] = true;
|
$recursive['recursive'] = true;
|
||||||
$body = '$tpl->getMacro("'.$name.'")->__invoke($tpl);';
|
$body = '$tpl->getMacro("' . $name . '")->__invoke($tpl);';
|
||||||
} else {
|
} else {
|
||||||
$body = '?>'.$macro["body"].'<?php';
|
$body = '?>' . $macro["body"] . '<?php';
|
||||||
}
|
}
|
||||||
return '$_tpl'.$n.' = $tpl->exchangeArray(' . Compiler::toArray($args) . ');' . PHP_EOL . $body . PHP_EOL . '$tpl->exchangeArray($_tpl'.$n.'); unset($_tpl'.$n.');';
|
return '$_tpl' . $n . ' = $tpl->exchangeArray(' . Compiler::toArray($args) . ');' . PHP_EOL . $body . PHP_EOL . '$tpl->exchangeArray($_tpl' . $n . '); unset($_tpl' . $n . ');';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1334,7 +1398,7 @@ class Template extends Render
|
|||||||
$arg = $colon = false;
|
$arg = $colon = false;
|
||||||
while ($tokens->valid()) {
|
while ($tokens->valid()) {
|
||||||
if (!$arg && $tokens->is(T_VARIABLE, T_STRING, "(", Tokenizer::MACRO_SCALAR, '"', Tokenizer::MACRO_UNARY, Tokenizer::MACRO_INCDEC)) {
|
if (!$arg && $tokens->is(T_VARIABLE, T_STRING, "(", Tokenizer::MACRO_SCALAR, '"', Tokenizer::MACRO_UNARY, Tokenizer::MACRO_INCDEC)) {
|
||||||
$_args .= $this->parseExp($tokens, true);
|
$_args .= $this->parseExpr($tokens);
|
||||||
$arg = true;
|
$arg = true;
|
||||||
$colon = false;
|
$colon = false;
|
||||||
} elseif (!$arg && $tokens->is('[')) {
|
} elseif (!$arg && $tokens->is('[')) {
|
||||||
@ -1367,7 +1431,7 @@ class Template extends Render
|
|||||||
{
|
{
|
||||||
if ($tokens->is(T_CONSTANT_ENCAPSED_STRING)) {
|
if ($tokens->is(T_CONSTANT_ENCAPSED_STRING)) {
|
||||||
if ($tokens->isNext('|')) {
|
if ($tokens->isNext('|')) {
|
||||||
return $this->parseExp($tokens, true);
|
return $this->parseExpr($tokens);
|
||||||
} else {
|
} else {
|
||||||
$str = $tokens->getAndNext();
|
$str = $tokens->getAndNext();
|
||||||
$static = stripslashes(substr($str, 1, -1));
|
$static = stripslashes(substr($str, 1, -1));
|
||||||
@ -1377,7 +1441,7 @@ class Template extends Render
|
|||||||
$static = $tokens->getAndNext();
|
$static = $tokens->getAndNext();
|
||||||
return '"' . addslashes($static) . '"';
|
return '"' . addslashes($static) . '"';
|
||||||
} else {
|
} else {
|
||||||
return $this->parseExp($tokens, true);
|
return $this->parseExpr($tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1403,12 +1467,12 @@ class Template extends Render
|
|||||||
}
|
}
|
||||||
if ($tokens->is("=")) {
|
if ($tokens->is("=")) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$params[$key] = $this->parseExp($tokens);
|
$params[$key] = $this->parseExpr($tokens);
|
||||||
} else {
|
} else {
|
||||||
$params[$key] = 'true';
|
$params[$key] = 'true';
|
||||||
}
|
}
|
||||||
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR, '"', '`', T_VARIABLE, "[", '(')) {
|
} elseif ($tokens->is(Tokenizer::MACRO_SCALAR, '"', '`', T_VARIABLE, "[", '(')) {
|
||||||
$params[] = $this->parseExp($tokens);
|
$params[] = $this->parseExpr($tokens);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ defined('T_TRAIT_C') || define('T_TRAIT_C', 365);
|
|||||||
/**
|
/**
|
||||||
* for PHP <5.5 compatible
|
* for PHP <5.5 compatible
|
||||||
*/
|
*/
|
||||||
defined('T_YIELD') || define('T_YIELD', 390);
|
defined('T_YIELD') || define('T_YIELD', 267);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each token have structure
|
* Each token have structure
|
||||||
|
@ -16,6 +16,15 @@ class TemplateTest extends TestCase
|
|||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->tpl('welcome.tpl', '<b>Welcome, {$username} ({$email})</b>');
|
$this->tpl('welcome.tpl', '<b>Welcome, {$username} ({$email})</b>');
|
||||||
|
$_GET['one'] = 'get1';
|
||||||
|
$_POST['one'] = 'post1';
|
||||||
|
$_REQUEST['one'] = 'request1';
|
||||||
|
$_FILES['one'] = 'files1';
|
||||||
|
$_SERVER['one'] = 'server1';
|
||||||
|
$_SESSION['one'] = 'session1';
|
||||||
|
$GLOBALS['one'] = 'globals1';
|
||||||
|
$_ENV['one'] = 'env1';
|
||||||
|
$_COOKIE['one'] = 'cookie1';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function providerVars()
|
public static function providerVars()
|
||||||
@ -687,10 +696,29 @@ class TemplateTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function providerAccessor() {
|
||||||
|
return array(
|
||||||
|
array('{$.get.one}', 'get1'),
|
||||||
|
array('{$.post.one}', 'post1'),
|
||||||
|
array('{$.request.one}', 'request1'),
|
||||||
|
array('{$.session.one}', 'session1'),
|
||||||
|
array('{$.files.one}', 'files1'),
|
||||||
|
array('{$.globals.one}', 'globals1'),
|
||||||
|
array('{$.cookie.one}', 'cookie1'),
|
||||||
|
array('{$.server.one}', 'server1'),
|
||||||
|
array('{$.const.PHP_EOL}', PHP_EOL),
|
||||||
|
array('{$.version}', Fenom::VERSION),
|
||||||
|
|
||||||
|
array('{$.get.one?}', '1'),
|
||||||
|
array('{$.get.one is set}', '1'),
|
||||||
|
array('{$.get.two is empty}', '1'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function _testSandbox()
|
public function _testSandbox()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
var_dump($this->fenom->compileCode('{if max(2, 4) > 1 && max(2, 3) < 1} block1 {else} block2 {/if}')->getBody());
|
var_dump($this->fenom->compileCode('{$.const.access?}')->getBody());
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
|
||||||
}
|
}
|
||||||
@ -910,5 +938,14 @@ class TemplateTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->exec($code, self::getVars(), $result);
|
$this->exec($code, self::getVars(), $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group accessor
|
||||||
|
* @dataProvider providerAccessor
|
||||||
|
*/
|
||||||
|
public function testAccessor($code, $result)
|
||||||
|
{
|
||||||
|
$this->exec($code, self::getVars(), $result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user