migrate to php8

This commit is contained in:
ivan shalganov 2023-02-05 21:59:04 +01:00
parent 065ccaec23
commit 84dac62a85
11 changed files with 1630 additions and 1888 deletions

View File

@ -11,15 +11,17 @@
} }
], ],
"require": { "require": {
"php": ">=5.3.0", "php": ">=8.0.0",
"ext-tokenizer": "*" "ext-tokenizer": "*"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "<6.0", "phpunit/phpunit": "9.*"
"satooshi/php-coveralls": "*"
}, },
"autoload": { "autoload": {
"psr-0": { "Fenom\\": "src/" }, "psr-4": { "Fenom\\": "src/Fenom" },
"classmap": [ "src/Fenom.php" ] "classmap": [ "src/Fenom.php" ]
},
"autoload-dev": {
"classmap": [ "tests/cases" ]
} }
} }

2786
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,6 @@
convertWarningsToExceptions="true" convertWarningsToExceptions="true"
processIsolation="false" processIsolation="false"
stopOnFailure="false" stopOnFailure="false"
syntaxCheck="false"
bootstrap="tests/autoload.php" bootstrap="tests/autoload.php"
> >
<php> <php>
@ -18,7 +17,7 @@
</php> </php>
<testsuites> <testsuites>
<testsuite > <testsuite name="tests">
<directory>./tests/</directory> <directory>./tests/</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
@ -29,14 +28,6 @@
</exclude> </exclude>
</groups> </groups>
<filter>
<whitelist>
<directory>./src/</directory>
</whitelist>
<blacklist>
<directory>./tests/</directory>
</blacklist>
</filter>
<logging> <logging>
<log type="coverage-clover" target="build/logs/clover.xml"/> <log type="coverage-clover" target="build/logs/clover.xml"/>
</logging> </logging>

View File

@ -8,7 +8,9 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
use Fenom\Error\CompileException; use Fenom\Error\CompileException;
use Fenom\Provider;
use Fenom\ProviderInterface; use Fenom\ProviderInterface;
use Fenom\Render;
use Fenom\Template; use Fenom\Template;
/** /**
@ -73,7 +75,7 @@ class Fenom
* @var int[] of possible options, as associative array * @var int[] of possible options, as associative array
* @see setOptions * @see setOptions
*/ */
private static $_options_list = array( private static $_options_list = [
"disable_accessor" => self::DENY_ACCESSOR, "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,
@ -87,71 +89,71 @@ class Fenom
"disable_php_calls" => self::DENY_PHP_CALLS, "disable_php_calls" => self::DENY_PHP_CALLS,
"disable_statics" => self::DENY_STATICS, "disable_statics" => self::DENY_STATICS,
"strip" => self::AUTO_STRIP, "strip" => self::AUTO_STRIP,
); ];
/** /**
* @var callable[] * @var callable[]
*/ */
public $pre_filters = array(); public array $pre_filters = [];
/** /**
* @var callable[] * @var callable[]
*/ */
public $filters = array(); public array $filters = [];
/** /**
* @var callable[] * @var callable[]
*/ */
public $tag_filters = array(); public array $tag_filters = [];
/** /**
* @var string[] * @var string[]
*/ */
public $call_filters = array(); public array $call_filters = [];
/** /**
* @var callable[] * @var callable[]
*/ */
public $post_filters = array(); public array $post_filters = [];
/** /**
* @var Fenom\Render[] Templates storage * @var Fenom\Render[] Templates storage
*/ */
protected $_storage = array(); protected array $_storage = [];
/** /**
* @var string compile directory * @var string compile directory
*/ */
protected $_compile_dir = "/tmp"; protected string $_compile_dir = "/tmp";
/** /**
* @var string compile prefix ID template * @var string compile prefix ID template
*/ */
protected $_compile_id; protected string $_compile_id;
/** /**
* @var string[] compile directory for custom provider * @var string[] compile directory for custom provider
*/ */
protected $_compiles = array(); protected array $_compiles = [];
/** /**
* @var int masked options * @var int masked options
*/ */
protected $_options = 0; protected int $_options = 0;
/** /**
* @var ProviderInterface * @var ProviderInterface
*/ */
private $_provider; private ProviderInterface $_provider;
/** /**
* @var Fenom\ProviderInterface[] * @var Fenom\ProviderInterface[]
*/ */
protected $_providers = array(); protected array $_providers = [];
/** /**
* @var string[] list of modifiers [modifier_name => callable] * @var string[] list of modifiers [modifier_name => callable]
*/ */
protected $_modifiers = array( protected array $_modifiers = [
"upper" => 'strtoupper', "upper" => 'strtoupper',
"up" => 'strtoupper', "up" => 'strtoupper',
"lower" => 'strtolower', "lower" => 'strtolower',
@ -174,12 +176,12 @@ class Fenom
"join" => 'Fenom\Modifier::join', "join" => 'Fenom\Modifier::join',
"in" => 'Fenom\Modifier::in', "in" => 'Fenom\Modifier::in',
"range" => 'Fenom\Modifier::range', "range" => 'Fenom\Modifier::range',
); ];
/** /**
* @var array of allowed PHP functions * @var array of allowed PHP functions
*/ */
protected $_allowed_funcs = array( protected array $_allowed_funcs = [
"count" => 1, "count" => 1,
"is_string" => 1, "is_string" => 1,
"is_array" => 1, "is_array" => 1,
@ -198,168 +200,168 @@ class Fenom
"nl2br" => 1, "nl2br" => 1,
"explode" => 1, "explode" => 1,
"implode" => 1 "implode" => 1
); ];
/** /**
* @var string[] the disabled functions by `disable_functions` PHP's option * @var string[] the disabled functions by `disable_functions` PHP's option
*/ */
protected $_disabled_funcs; protected array $_disabled_funcs = [];
/** /**
* @var array[] of compilers and functions * @var array[] of compilers and functions
*/ */
protected $_actions = array( protected array $_actions = [
'foreach' => array( // {foreach ...} {break} {continue} {foreachelse} {/foreach} 'foreach' => [ // {foreach ...} {break} {continue} {foreachelse} {/foreach}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::foreachOpen', 'open' => 'Fenom\Compiler::foreachOpen',
'close' => 'Fenom\Compiler::foreachClose', 'close' => 'Fenom\Compiler::foreachClose',
'tags' => array( 'tags' => [
'foreachelse' => 'Fenom\Compiler::foreachElse', 'foreachelse' => 'Fenom\Compiler::foreachElse',
'break' => 'Fenom\Compiler::tagBreak', 'break' => 'Fenom\Compiler::tagBreak',
'continue' => 'Fenom\Compiler::tagContinue', 'continue' => 'Fenom\Compiler::tagContinue',
), ],
'float_tags' => array('break' => 1, 'continue' => 1) 'float_tags' => ['break' => 1, 'continue' => 1]
), ],
'if' => array( // {if ...} {elseif ...} {else} {/if} 'if' => [ // {if ...} {elseif ...} {else} {/if}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::ifOpen', 'open' => 'Fenom\Compiler::ifOpen',
'close' => 'Fenom\Compiler::stdClose', 'close' => 'Fenom\Compiler::stdClose',
'tags' => array( 'tags' => [
'elseif' => 'Fenom\Compiler::tagElseIf', 'elseif' => 'Fenom\Compiler::tagElseIf',
'else' => 'Fenom\Compiler::tagElse' 'else' => 'Fenom\Compiler::tagElse'
) ]
), ],
'switch' => array( // {switch ...} {case ..., ...} {default} {/switch} 'switch' => [ // {switch ...} {case ..., ...} {default} {/switch}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::switchOpen', 'open' => 'Fenom\Compiler::switchOpen',
'close' => 'Fenom\Compiler::switchClose', 'close' => 'Fenom\Compiler::switchClose',
'tags' => array( 'tags' => [
'case' => 'Fenom\Compiler::tagCase', 'case' => 'Fenom\Compiler::tagCase',
'default' => 'Fenom\Compiler::tagDefault' 'default' => 'Fenom\Compiler::tagDefault'
), ],
'float_tags' => array('break' => 1) 'float_tags' => ['break' => 1]
), ],
'for' => array( // {for ...} {break} {continue} {/for} 'for' => [ // {for ...} {break} {continue} {/for}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::forOpen', 'open' => 'Fenom\Compiler::forOpen',
'close' => 'Fenom\Compiler::forClose', 'close' => 'Fenom\Compiler::forClose',
'tags' => array( 'tags' => [
'forelse' => 'Fenom\Compiler::forElse', 'forelse' => 'Fenom\Compiler::forElse',
'break' => 'Fenom\Compiler::tagBreak', 'break' => 'Fenom\Compiler::tagBreak',
'continue' => 'Fenom\Compiler::tagContinue', 'continue' => 'Fenom\Compiler::tagContinue',
), ],
'float_tags' => array('break' => 1, 'continue' => 1) 'float_tags' => ['break' => 1, 'continue' => 1]
), ],
'while' => array( // {while ...} {break} {continue} {/while} 'while' => [ // {while ...} {break} {continue} {/while}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::whileOpen', 'open' => 'Fenom\Compiler::whileOpen',
'close' => 'Fenom\Compiler::stdClose', 'close' => 'Fenom\Compiler::stdClose',
'tags' => array( 'tags' => [
'break' => 'Fenom\Compiler::tagBreak', 'break' => 'Fenom\Compiler::tagBreak',
'continue' => 'Fenom\Compiler::tagContinue', 'continue' => 'Fenom\Compiler::tagContinue',
), ],
'float_tags' => array('break' => 1, 'continue' => 1) 'float_tags' => ['break' => 1, 'continue' => 1]
), ],
'include' => array( // {include ...} 'include' => [ // {include ...}
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagInclude' 'parser' => 'Fenom\Compiler::tagInclude'
), ],
'insert' => array( // {include ...} 'insert' => [ // {include ...}
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagInsert' 'parser' => 'Fenom\Compiler::tagInsert'
), ],
'var' => array( // {var ...} 'var' => [ // {var ...}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::setOpen', 'open' => 'Fenom\Compiler::setOpen',
'close' => 'Fenom\Compiler::setClose' 'close' => 'Fenom\Compiler::setClose'
), ],
'set' => array( // {set ...} 'set' => [ // {set ...}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::setOpen', 'open' => 'Fenom\Compiler::setOpen',
'close' => 'Fenom\Compiler::setClose' 'close' => 'Fenom\Compiler::setClose'
), ],
'add' => array( // {add ...} 'add' => [ // {add ...}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::setOpen', 'open' => 'Fenom\Compiler::setOpen',
'close' => 'Fenom\Compiler::setClose' 'close' => 'Fenom\Compiler::setClose'
), ],
'do' => array( // {do ...} 'do' => [ // {do ...}
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagDo' 'parser' => 'Fenom\Compiler::tagDo'
), ],
'block' => array( // {block ...} {parent} {/block} 'block' => [ // {block ...} {parent} {/block}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::tagBlockOpen', 'open' => 'Fenom\Compiler::tagBlockOpen',
'close' => 'Fenom\Compiler::tagBlockClose', 'close' => 'Fenom\Compiler::tagBlockClose',
'tags' => array('parent' => 'Fenom\Compiler::tagParent'), 'tags' => ['parent' => 'Fenom\Compiler::tagParent'],
'float_tags' => array('parent' => 1) 'float_tags' => ['parent' => 1]
), ],
'extends' => array( // {extends ...} 'extends' => [ // {extends ...}
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagExtends' 'parser' => 'Fenom\Compiler::tagExtends'
), ],
'use' => array( // {use} 'use' => [ // {use}
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagUse' 'parser' => 'Fenom\Compiler::tagUse'
), ],
'filter' => array( // {filter} ... {/filter} 'filter' => [ // {filter} ... {/filter}
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::filterOpen', 'open' => 'Fenom\Compiler::filterOpen',
'close' => 'Fenom\Compiler::filterClose' 'close' => 'Fenom\Compiler::filterClose'
), ],
'macro' => array( 'macro' => [
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::macroOpen', 'open' => 'Fenom\Compiler::macroOpen',
'close' => 'Fenom\Compiler::macroClose' 'close' => 'Fenom\Compiler::macroClose'
), ],
'import' => array( 'import' => [
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagImport' 'parser' => 'Fenom\Compiler::tagImport'
), ],
'cycle' => array( 'cycle' => [
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagCycle' 'parser' => 'Fenom\Compiler::tagCycle'
), ],
'raw' => array( 'raw' => [
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagRaw' 'parser' => 'Fenom\Compiler::tagRaw'
), ],
'autoescape' => array( // deprecated 'autoescape' => [ // deprecated
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::escapeOpen', 'open' => 'Fenom\Compiler::escapeOpen',
'close' => 'Fenom\Compiler::nope' 'close' => 'Fenom\Compiler::nope'
), ],
'escape' => array( 'escape' => [
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::escapeOpen', 'open' => 'Fenom\Compiler::escapeOpen',
'close' => 'Fenom\Compiler::nope' 'close' => 'Fenom\Compiler::nope'
), ],
'strip' => array( 'strip' => [
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::stripOpen', 'open' => 'Fenom\Compiler::stripOpen',
'close' => 'Fenom\Compiler::nope' 'close' => 'Fenom\Compiler::nope'
), ],
'ignore' => array( 'ignore' => [
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::ignoreOpen', 'open' => 'Fenom\Compiler::ignoreOpen',
'close' => 'Fenom\Compiler::nope' 'close' => 'Fenom\Compiler::nope'
), ],
'unset' => array( 'unset' => [
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagUnset' 'parser' => 'Fenom\Compiler::tagUnset'
), ],
'paste' => array( // {include ...} 'paste' => [ // {include ...}
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagPaste' 'parser' => 'Fenom\Compiler::tagPaste'
), ],
); ];
/** /**
* List of tests * List of tests
* @see https://github.com/bzick/fenom/blob/develop/docs/operators.md#test-operator * @see https://github.com/bzick/fenom/blob/develop/docs/operators.md#test-operator
* @var array * @var array
*/ */
protected $_tests = array( protected array $_tests = [
'integer' => 'is_int(%s)', 'integer' => 'is_int(%s)',
'int' => 'is_int(%s)', 'int' => 'is_int(%s)',
'float' => 'is_float(%s)', 'float' => 'is_float(%s)',
@ -385,9 +387,9 @@ class Fenom
'odd' => '(%s & 1)', 'odd' => '(%s & 1)',
'even' => '!(%s %% 2)', 'even' => '!(%s %% 2)',
'third' => '!(%s %% 3)' 'third' => '!(%s %% 3)'
); ];
protected $_accessors = array( protected array $_accessors = [
'get' => 'Fenom\Accessor::getVar', 'get' => 'Fenom\Accessor::getVar',
'env' => 'Fenom\Accessor::getVar', 'env' => 'Fenom\Accessor::getVar',
'post' => 'Fenom\Accessor::getVar', 'post' => 'Fenom\Accessor::getVar',
@ -405,7 +407,7 @@ class Fenom
'tag' => 'Fenom\Accessor::Tag', 'tag' => 'Fenom\Accessor::Tag',
'fetch' => 'Fenom\Accessor::fetch', 'fetch' => 'Fenom\Accessor::fetch',
'block' => 'Fenom\Accessor::block', 'block' => 'Fenom\Accessor::block',
); ];
/** /**
* Just factory * Just factory
@ -416,7 +418,11 @@ class Fenom
* @throws InvalidArgumentException * @throws InvalidArgumentException
* @return Fenom * @return Fenom
*/ */
public static function factory($source, $compile_dir = '/tmp', $options = 0) public static function factory(
string|Fenom\ProviderInterface $source,
string $compile_dir = '/tmp',
int|array $options = 0
): Fenom
{ {
if (is_string($source)) { if (is_string($source)) {
$provider = new Fenom\Provider($source); $provider = new Fenom\Provider($source);
@ -426,7 +432,6 @@ class Fenom
throw new InvalidArgumentException("Source must be a valid path or provider object"); throw new InvalidArgumentException("Source must be a valid path or provider object");
} }
$fenom = new static($provider); $fenom = new static($provider);
/* @var Fenom $fenom */
$fenom->setCompileDir($compile_dir); $fenom->setCompileDir($compile_dir);
if ($options) { if ($options) {
$fenom->setOptions($options); $fenom->setOptions($options);
@ -447,9 +452,9 @@ class Fenom
* *
* @param string $dir directory to store compiled templates in * @param string $dir directory to store compiled templates in
* @throws LogicException * @throws LogicException
* @return Fenom * @return $this
*/ */
public function setCompileDir($dir) public function setCompileDir(string $dir): static
{ {
if (!is_writable($dir)) { if (!is_writable($dir)) {
throw new LogicException("Cache directory $dir is not writable"); throw new LogicException("Cache directory $dir is not writable");
@ -462,9 +467,9 @@ class Fenom
* Set compile prefix ID template * Set compile prefix ID template
* *
* @param string $id prefix ID to store compiled templates * @param string $id prefix ID to store compiled templates
* @return Fenom * @return $this
*/ */
public function setCompileId($id) public function setCompileId(string $id): static
{ {
$this->_compile_id = $id; $this->_compile_id = $id;
return $this; return $this;
@ -473,15 +478,18 @@ class Fenom
/** /**
* *
* @param callable $cb * @param callable $cb
* @return self * @return $this
*/ */
public function addPreFilter($cb) public function addPreFilter(callable $cb): static
{ {
$this->pre_filters[] = $cb; $this->pre_filters[] = $cb;
return $this; return $this;
} }
public function getPreFilters() /**
* @return callable[]
*/
public function getPreFilters(): array
{ {
return $this->pre_filters; return $this->pre_filters;
} }
@ -489,16 +497,18 @@ class Fenom
/** /**
* *
* @param callable $cb * @param callable $cb
* @return self * @return $this
*/ */
public function addPostFilter($cb) public function addPostFilter(callable $cb): static
{ {
$this->post_filters[] = $cb; $this->post_filters[] = $cb;
return $this; return $this;
} }
/**
public function getPostFilters() * @return callable[]
*/
public function getPostFilters(): array
{ {
return $this->post_filters; return $this->post_filters;
} }
@ -507,14 +517,14 @@ class Fenom
* @param callable $cb * @param callable $cb
* @return self * @return self
*/ */
public function addFilter($cb) public function addFilter(callable $cb): static
{ {
$this->filters[] = $cb; $this->filters[] = $cb;
return $this; return $this;
} }
public function getFilters() public function getFilters(): array
{ {
return $this->filters; return $this->filters;
} }
@ -523,14 +533,14 @@ class Fenom
* @param callable $cb * @param callable $cb
* @return self * @return self
*/ */
public function addTagFilter($cb) public function addTagFilter(callable $cb): static
{ {
$this->tag_filters[] = $cb; $this->tag_filters[] = $cb;
return $this; return $this;
} }
public function getTagFilters() public function getTagFilters(): array
{ {
return $this->tag_filters; return $this->tag_filters;
} }
@ -542,7 +552,7 @@ class Fenom
* @param callable $callback the modifier callback * @param callable $callback the modifier callback
* @return Fenom * @return Fenom
*/ */
public function addModifier($modifier, $callback) public function addModifier(string $modifier, callable $callback): static
{ {
$this->_modifiers[$modifier] = $callback; $this->_modifiers[$modifier] = $callback;
return $this; return $this;
@ -555,7 +565,7 @@ class Fenom
* @param callable $parser * @param callable $parser
* @return Fenom * @return Fenom
*/ */
public function addCompiler($compiler, $parser) public function addCompiler(string $compiler, callable $parser): static
{ {
$this->_actions[$compiler] = array( $this->_actions[$compiler] = array(
'type' => self::INLINE_COMPILER, 'type' => self::INLINE_COMPILER,
@ -569,7 +579,7 @@ class Fenom
* @param string|object $storage * @param string|object $storage
* @return $this * @return $this
*/ */
public function addCompilerSmart($compiler, $storage) public function addCompilerSmart(string $compiler, string|object $storage): static
{ {
if (method_exists($storage, "tag" . $compiler)) { if (method_exists($storage, "tag" . $compiler)) {
$this->_actions[$compiler] = array( $this->_actions[$compiler] = array(
@ -585,11 +595,17 @@ class Fenom
* *
* @param string $compiler * @param string $compiler
* @param callable $open_parser * @param callable $open_parser
* @param callable|string $close_parser * @param callable $close_parser
* @param array $tags * @param array $tags
* @return Fenom * @return Fenom
*/ */
public function addBlockCompiler($compiler, $open_parser, $close_parser = self::DEFAULT_CLOSE_COMPILER, array $tags = array()) { public function addBlockCompiler(
string $compiler,
callable $open_parser,
callable $close_parser = self::DEFAULT_CLOSE_COMPILER,
array $tags = []
): static
{
$this->_actions[$compiler] = array( $this->_actions[$compiler] = array(
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => $open_parser, 'open' => $open_parser,
@ -600,14 +616,19 @@ class Fenom
} }
/** /**
* @param $compiler * @param string $compiler
* @param $storage * @param string|object $storage
* @param array $tags * @param array $tags
* @param array $floats * @param array $floats
* @throws LogicException * @throws LogicException
* @return Fenom * @return Fenom
*/ */
public function addBlockCompilerSmart($compiler, $storage, array $tags, array $floats = array()) public function addBlockCompilerSmart(
string $compiler,
string|object $storage,
array $tags,
array $floats = []
): static
{ {
$c = array( $c = array(
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
@ -641,10 +662,10 @@ class Fenom
/** /**
* @param string $function * @param string $function
* @param callable $callback * @param callable $callback
* @param callable|string $parser * @param callable $parser
* @return Fenom * @return Fenom
*/ */
public function addFunction($function, $callback, $parser = self::DEFAULT_FUNC_PARSER) public function addFunction(string $function, callable $callback, callable $parser = self::DEFAULT_FUNC_PARSER): static
{ {
$this->_actions[$function] = array( $this->_actions[$function] = array(
'type' => self::INLINE_FUNCTION, 'type' => self::INLINE_FUNCTION,
@ -659,7 +680,7 @@ class Fenom
* @param callable $callback * @param callable $callback
* @return Fenom * @return Fenom
*/ */
public function addFunctionSmart($function, $callback) public function addFunctionSmart(string $function, callable $callback): static
{ {
$this->_actions[$function] = array( $this->_actions[$function] = array(
'type' => self::INLINE_FUNCTION, 'type' => self::INLINE_FUNCTION,
@ -672,11 +693,16 @@ class Fenom
/** /**
* @param string $function * @param string $function
* @param callable $callback * @param callable $callback
* @param callable|string $parser_open * @param callable $parser_open
* @param callable|string $parser_close * @param callable $parser_close
* @return Fenom * @return Fenom
*/ */
public function addBlockFunction($function, $callback, $parser_open = self::DEFAULT_FUNC_OPEN, $parser_close = self::DEFAULT_FUNC_CLOSE) public function addBlockFunction(
string $function,
callable $callback,
callable $parser_open = self::DEFAULT_FUNC_OPEN,
callable $parser_close = self::DEFAULT_FUNC_CLOSE
): static
{ {
$this->_actions[$function] = array( $this->_actions[$function] = array(
'type' => self::BLOCK_FUNCTION, 'type' => self::BLOCK_FUNCTION,
@ -691,7 +717,7 @@ class Fenom
* @param array $funcs * @param array $funcs
* @return Fenom * @return Fenom
*/ */
public function addAllowedFunctions(array $funcs) public function addAllowedFunctions(array $funcs): static
{ {
$this->_allowed_funcs = $this->_allowed_funcs + array_flip($funcs); $this->_allowed_funcs = $this->_allowed_funcs + array_flip($funcs);
return $this; return $this;
@ -700,31 +726,32 @@ class Fenom
/** /**
* Add custom test * Add custom test
* @param string $name test name * @param string $name test name
* @param string $code test PHP code. Code may contains placeholder %s, which will be replaced by test-value. For example: is_callable(%s) * @param string $code test PHP code. Code may contain placeholder %s, which will be replaced by test-value. For example: is_callable(%s)
*/ */
public function addTest($name, $code) public function addTest(string $name, string $code): static
{ {
$this->_tests[$name] = $code; $this->_tests[$name] = $code;
return $this;
} }
/** /**
* Get test code by name * Get test code by name
* @param string $name * @param string $name
* @return string|bool * @return string
*/ */
public function getTest($name) public function getTest(string $name): string
{ {
return isset($this->_tests[$name]) ? $this->_tests[$name] : false; return $this->_tests[$name] ?? "";
} }
/** /**
* Return modifier function * Return modifier function
* *
* @param string $modifier * @param string $modifier
* @param Fenom\Template $template * @param Template|null $template
* @return mixed * @return mixed
*/ */
public function getModifier($modifier, Template $template = null) public function getModifier(string $modifier, Fenom\Template $template = null): static
{ {
if (isset($this->_modifiers[$modifier])) { if (isset($this->_modifiers[$modifier])) {
return $this->_modifiers[$modifier]; return $this->_modifiers[$modifier];
@ -741,7 +768,7 @@ class Fenom
* @param Fenom\Template $template * @param Fenom\Template $template
* @return bool * @return bool
*/ */
protected function _loadModifier($modifier, $template) protected function _loadModifier(string $modifier, Fenom\Template $template): bool
{ {
return false; return false;
} }
@ -750,10 +777,10 @@ class Fenom
* Returns tag info * Returns tag info
* *
* @param string $tag * @param string $tag
* @param Fenom\Template $template * @param Template|null $template
* @return string|bool * @return array|null
*/ */
public function getTag($tag, Template $template = null) public function getTag(string $tag, Template $template = null): ?array
{ {
if (isset($this->_actions[$tag])) { if (isset($this->_actions[$tag])) {
return $this->_actions[$tag]; return $this->_actions[$tag];
@ -766,11 +793,11 @@ class Fenom
* Tags autoloader * Tags autoloader
* @param string $tag * @param string $tag
* @param Fenom\Template $template * @param Fenom\Template $template
* @return bool * @return array|null
*/ */
protected function _loadTag($tag, $template) protected function _loadTag(string $tag, Template $template): ?array
{ {
return false; return null;
} }
/** /**
@ -779,13 +806,12 @@ class Fenom
* @param string $function the function name * @param string $function the function name
* @return bool * @return bool
*/ */
public function isAllowedFunction($function) public function isAllowedFunction(string $function): bool
{ {
$function = (string) $function;
$allow = ($this->_options & self::DENY_NATIVE_FUNCS) $allow = ($this->_options & self::DENY_NATIVE_FUNCS)
? isset($this->_allowed_funcs[$function]) ? isset($this->_allowed_funcs[$function])
: function_exists($function); : function_exists($function);
return $allow && !in_array($function, $this->getDisabledFuncs(), true); return $allow && !in_array($function, $this->_getDisabledFuncs(), true);
} }
/** /**
@ -793,18 +819,8 @@ class Fenom
* *
* @return string[] * @return string[]
*/ */
protected function _getDisabledFuncs() protected function _getDisabledFuncs(): array
{ {
if (!is_array($this->_disabled_funcs)) {
$disabled = ini_get('disable_functions');
// adds execution functions to disabled for security
$this->_disabled_funcs = array_merge(
empty($disabled) ? [] : explode(',', $disabled),
array('exec', 'system', 'passthru', 'shell_exec', 'pcntl_exec', 'proc_open', 'popen'),
array('call_user_func', 'call_user_func_array')
);
}
return $this->_disabled_funcs; return $this->_disabled_funcs;
} }
@ -812,9 +828,9 @@ class Fenom
* @param string $tag * @param string $tag
* @return array * @return array
*/ */
public function getTagOwners($tag) public function getTagOwners(string $tag): array
{ {
$tags = array(); $tags = [];
foreach ($this->_actions as $owner => $params) { foreach ($this->_actions as $owner => $params) {
if (isset($params["tags"][$tag])) { if (isset($params["tags"][$tag])) {
$tags[] = $owner; $tags[] = $owner;
@ -828,10 +844,10 @@ class Fenom
* *
* @param string $scm scheme name * @param string $scm scheme name
* @param Fenom\ProviderInterface $provider provider object * @param Fenom\ProviderInterface $provider provider object
* @param string $compile_path * @param string|null $compile_path
* @return $this * @return $this
*/ */
public function addProvider($scm, \Fenom\ProviderInterface $provider, $compile_path = null) public function addProvider(string $scm, ProviderInterface $provider, string $compile_path = null): static
{ {
$this->_providers[$scm] = $provider; $this->_providers[$scm] = $provider;
if ($compile_path) { if ($compile_path) {
@ -845,7 +861,7 @@ class Fenom
* @param int|array $options * @param int|array $options
* @return $this * @return $this
*/ */
public function setOptions($options) public function setOptions(int|array $options): static
{ {
if (is_array($options)) { if (is_array($options)) {
$options = self::_makeMask($options, self::$_options_list, $this->_options); $options = self::_makeMask($options, self::$_options_list, $this->_options);
@ -859,7 +875,7 @@ class Fenom
* Get options as bits * Get options as bits
* @return int * @return int
*/ */
public function getOptions() public function getOptions(): int
{ {
return $this->_options; return $this->_options;
} }
@ -870,7 +886,7 @@ class Fenom
* @param callable $parser * @param callable $parser
* @return Fenom * @return Fenom
*/ */
public function addAccessor($name, $parser) public function addAccessor(string $name, callable $parser): static
{ {
$this->_accessors[$name] = $parser; $this->_accessors[$name] = $parser;
return $this; return $this;
@ -883,7 +899,7 @@ class Fenom
* @param string $parser * @param string $parser
* @return Fenom * @return Fenom
*/ */
public function addAccessorSmart($name, $accessor, $parser = self::ACCESSOR_VAR) public function addAccessorSmart(string $name, mixed $accessor, string $parser = self::ACCESSOR_VAR): static
{ {
$this->_accessors[$name] = array( $this->_accessors[$name] = array(
"accessor" => $accessor, "accessor" => $accessor,
@ -898,7 +914,7 @@ class Fenom
* @param callable $callback * @param callable $callback
* @return Fenom * @return Fenom
*/ */
public function addAccessorCallback($name, $callback) public function addAccessorCallback(string $name, callable $callback): static
{ {
$this->_accessors[$name] = array( $this->_accessors[$name] = array(
"callback" => $callback "callback" => $callback
@ -911,7 +927,7 @@ class Fenom
* @param string $name * @param string $name
* @return Fenom * @return Fenom
*/ */
public function removeAccessor($name) public function removeAccessor(string $name): static
{ {
unset($this->_accessors[$name]); unset($this->_accessors[$name]);
return $this; return $this;
@ -920,10 +936,10 @@ class Fenom
/** /**
* Get an accessor * Get an accessor
* @param string $name * @param string $name
* @param string $key * @param string|null $key
* @return callable * @return callable|null
*/ */
public function getAccessor($name, $key = null) public function getAccessor(string $name,string $key = null): ?callable
{ {
if(isset($this->_accessors[$name])) { if(isset($this->_accessors[$name])) {
if($key) { if($key) {
@ -932,7 +948,7 @@ class Fenom
return $this->_accessors[$name]; return $this->_accessors[$name];
} }
} else { } else {
return false; return null;
} }
} }
@ -942,18 +958,18 @@ class Fenom
* @param string $pattern * @param string $pattern
* @return $this * @return $this
*/ */
public function addCallFilter($pattern) public function addCallFilter(string $pattern): static
{ {
$this->call_filters[] = $pattern; $this->call_filters[] = $pattern;
return $this; return $this;
} }
/** /**
* @param bool|string $scm * @param string|null $scm
* @return Fenom\ProviderInterface * @return ProviderInterface
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
public function getProvider($scm = false) public function getProvider(string $scm = null): Fenom\ProviderInterface
{ {
if ($scm) { if ($scm) {
if (isset($this->_providers[$scm])) { if (isset($this->_providers[$scm])) {
@ -971,7 +987,7 @@ class Fenom
* *
* @return Fenom\Template * @return Fenom\Template
*/ */
public function getRawTemplate(Template $parent = null) public function getRawTemplate(Template $parent = null): Template
{ {
return new Template($this, $this->_options, $parent); return new Template($this, $this->_options, $parent);
} }
@ -983,20 +999,22 @@ class Fenom
* If it is array of names of templates they will be extended from left to right. * If it is array of names of templates they will be extended from left to right.
* @param array $vars array of data for template * @param array $vars array of data for template
* @return Fenom\Render * @return Fenom\Render
* @throws CompileException
*/ */
public function display($template, array $vars = array()) public function display(string|array $template, array $vars = array()): Fenom\Render
{ {
return $this->getTemplate($template)->display($vars); return $this->getTemplate($template)->display($vars);
} }
/** /**
* *
* @param string|array $template name of template. * @param array|string $template name of template.
* If it is array of names of templates they will be extended from left to right. * If it is array of names of templates they will be extended from left to right.
* @param array $vars array of data for template * @param array $vars array of data for template
* @return mixed * @return mixed
* @throws Exception
*/ */
public function fetch($template, array $vars = array()) public function fetch(array|string $template, array $vars = array()): mixed
{ {
return $this->getTemplate($template)->fetch($vars); return $this->getTemplate($template)->fetch($vars);
} }
@ -1004,14 +1022,15 @@ class Fenom
/** /**
* Creates pipe-line of template's data to callback * Creates pipe-line of template's data to callback
* @note Method not works correctly in old PHP 5.3.* * @note Method not works correctly in old PHP 5.3.*
* @param string|array $template name of the template. * @param array|string $template name of the template.
* If it is array of names of templates they will be extended from left to right. * If it is array of names of templates they will be extended from left to right.
* @param callable $callback template's data handler * @param callable $callback template's data handler
* @param array $vars * @param array $vars
* @param float $chunk amount of bytes of chunk * @param int $chunk amount of bytes of chunk
* @return array * @return array
* @throws CompileException
*/ */
public function pipe($template, $callback, array $vars = array(), $chunk = 1e6) public function pipe(array|string $template, callable $callback, array $vars = array(), int $chunk = 1_000_000): array
{ {
ob_start($callback, $chunk, PHP_OUTPUT_HANDLER_STDFLAGS); ob_start($callback, $chunk, PHP_OUTPUT_HANDLER_STDFLAGS);
$data = $this->getTemplate($template)->display($vars); $data = $this->getTemplate($template)->display($vars);
@ -1022,11 +1041,12 @@ class Fenom
/** /**
* Get template by name * Get template by name
* *
* @param string $template template name with schema * @param string|array $template template name with schema
* @param int $options additional options and flags * @param int $options additional options and flags
* @return Fenom\Template * @return Fenom\Render
* @throws CompileException
*/ */
public function getTemplate($template, $options = 0) public function getTemplate(string|array $template, int $options = 0): Render
{ {
$options |= $this->_options; $options |= $this->_options;
if (is_array($template)) { if (is_array($template)) {
@ -1054,7 +1074,7 @@ class Fenom
* @param string $template * @param string $template
* @return bool * @return bool
*/ */
public function templateExists($template) public function templateExists(string $template): bool
{ {
$key = $this->_options . "@" . $template; $key = $this->_options . "@" . $template;
if (isset($this->_storage[$key])) { // already loaded if (isset($this->_storage[$key])) { // already loaded
@ -1076,8 +1096,9 @@ class Fenom
* @param string $template * @param string $template
* @param int $opts * @param int $opts
* @return Fenom\Render * @return Fenom\Render
* @throws CompileException
*/ */
protected function _load($template, $opts) protected function _load(string $template, int $opts): Render
{ {
$file_name = $this->getCompileName($template, $opts); $file_name = $this->getCompileName($template, $opts);
if (is_file($this->_compile_dir . "/" . $file_name)) { if (is_file($this->_compile_dir . "/" . $file_name)) {
@ -1101,7 +1122,7 @@ class Fenom
* @param int $options additional options * @param int $options additional options
* @return string * @return string
*/ */
public function getCompileName($tpl, $options = 0) public function getCompileName(array|string $tpl, int $options = 0): string
{ {
$options = $this->_options | $options; $options = $this->_options | $options;
if (is_array($tpl)) { if (is_array($tpl)) {
@ -1123,13 +1144,13 @@ class Fenom
/** /**
* Compile and save template * Compile and save template
* *
* @param string|array $tpl * @param array|string $tpl
* @param bool $store store template on disk * @param bool $store store template on disk
* @param int $options * @param int $options
* @return Template
* @throws CompileException * @throws CompileException
* @return \Fenom\Template
*/ */
public function compile($tpl, $store = true, $options = 0) public function compile(array|string $tpl, bool $store = true, int $options = 0): Template
{ {
if (is_string($tpl)) { if (is_string($tpl)) {
$template = $this->getRawTemplate()->load($tpl); $template = $this->getRawTemplate()->load($tpl);
@ -1157,17 +1178,17 @@ class Fenom
/** /**
* Flush internal template in-memory-cache * Flush internal template in-memory-cache
*/ */
public function flush() public function flush(): void
{ {
$this->_storage = array(); $this->_storage = [];
} }
/** /**
* Remove all compiled templates * Remove all compiled templates
*/ */
public function clearAllCompiles() public function clearAllCompiles(): void
{ {
\Fenom\Provider::clean($this->_compile_dir); Provider::clean($this->_compile_dir);
$this->flush(); $this->flush();
} }
@ -1178,7 +1199,7 @@ class Fenom
* @param string $name * @param string $name
* @return Fenom\Template * @return Fenom\Template
*/ */
public function compileCode($code, $name = 'Runtime compile') public function compileCode(string $code, string $name = 'Runtime compile'): Template
{ {
return $this->getRawTemplate()->source($name, $code); return $this->getRawTemplate()->source($name, $code);
} }
@ -1191,9 +1212,9 @@ class Fenom
* @param array $options possible values, ["a" => 0b001, "b" => 0b010, "c" => 0b100] * @param array $options possible values, ["a" => 0b001, "b" => 0b010, "c" => 0b100]
* @param int $mask the initial value of the mask * @param int $mask the initial value of the mask
* @return int result, ( $mask | a ) & ~b * @return int result, ( $mask | a ) & ~b
* @throws \RuntimeException if key from custom assoc doesn't exists into possible values * @throws \RuntimeException if key from custom assoc doesn't exist into possible values
*/ */
private static function _makeMask(array $values, array $options, $mask = 0) private static function _makeMask(array $values, array $options, int $mask = 0): int
{ {
foreach ($values as $key => $value) { foreach ($values as $key => $value) {
if (isset($options[$key])) { if (isset($options[$key])) {
@ -1208,24 +1229,4 @@ class Fenom
} }
return $mask; return $mask;
} }
/**
* Register PSR-0 autoload
* @param string $dir custom directory for autoloading, if NULL autoload itself
* @return bool
*/
public static function registerAutoload($dir = null)
{
if (!$dir) {
$dir = __DIR__;
}
return spl_autoload_register(
function ($classname) use ($dir) {
$file = $dir . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $classname) . '.php';
if (is_file($file)) {
require_once $file;
}
}
);
}
} }

View File

@ -84,7 +84,7 @@ class Accessor {
*/ */
public static function getVar(Tokenizer $tokens, Template $tpl) public static function getVar(Tokenizer $tokens, Template $tpl)
{ {
$name = $tokens->prev[Tokenizer::TEXT]; $name = $tokens->prevToken()[Tokenizer::TEXT];
if(isset(self::$vars[$name])) { if(isset(self::$vars[$name])) {
$var = $tpl->parseVariable($tokens, self::$vars[$name]); $var = $tpl->parseVariable($tokens, self::$vars[$name]);
return "(isset($var) ? $var : null)"; return "(isset($var) ? $var : null)";

View File

@ -24,7 +24,7 @@ class UnexpectedTokenException extends \RuntimeException
} else { } else {
$expect = ""; $expect = "";
} }
if (!$tokens->curr) { if (!$tokens->currToken()) {
$this->message = "Unexpected end of " . ($where ? : "expression") . "$expect"; $this->message = "Unexpected end of " . ($where ? : "expression") . "$expect";
} else { } else {
$this->message = "Unexpected token '" . $tokens->current() . "' in " . ($where ? : "expression") . "$expect"; $this->message = "Unexpected token '" . $tokens->current() . "' in " . ($where ? : "expression") . "$expect";

View File

@ -951,8 +951,8 @@ class Template extends Render
$code .= '->' . $tokens->next()->getAndNext(); $code .= '->' . $tokens->next()->getAndNext();
} }
if ($tokens->current() === "." || $tokens->current() === "[") { if ($tokens->current() === "." || $tokens->current() === "[") {
$code = substr($code, 0, -strlen($tokens->prev[1])); $code = substr($code, 0, -strlen($tokens->prevToken()[1]));
$code .= $this->parseVariable($tokens, $tokens->prev[1]); $code .= $this->parseVariable($tokens, $tokens->prevToken()[1]);
} }
} while ($tokens->is('(', T_OBJECT_OPERATOR)); } while ($tokens->is('(', T_OBJECT_OPERATOR));

View File

@ -19,9 +19,6 @@ use Fenom\Error\UnexpectedTokenException;
* - Line number of the token * - Line number of the token
* *
* @see http://php.net/tokenizer * @see http://php.net/tokenizer
* @property array $prev the previous token
* @property array $curr the current token
* @property array $next the next token
* *
* @package Fenom * @package Fenom
* @author Ivan Shalganov <a.cobest@gmail.com> * @author Ivan Shalganov <a.cobest@gmail.com>
@ -70,18 +67,18 @@ class Tokenizer
*/ */
const MACRO_COND = 1008; const MACRO_COND = 1008;
public $tokens; public array $tokens;
public $p = 0; public int $p = 0;
public $quotes = 0; public int $quotes = 0;
private $_max = 0; private int $_max;
private $_last_no = 0; private mixed $_last_no;
/** /**
* @see http://docs.php.net/manual/en/tokens.php * @see http://docs.php.net/manual/en/tokens.php
* @var array groups of tokens * @var array groups of tokens
*/ */
public static $macros = array( public static array $macros = [
self::MACRO_STRING => array( self::MACRO_STRING => [
\T_ABSTRACT => 1, \T_ARRAY => 1, \T_AS => 1, \T_BREAK => 1, \T_ABSTRACT => 1, \T_ARRAY => 1, \T_AS => 1, \T_BREAK => 1,
\T_CASE => 1, \T_CATCH => 1, \T_CLASS => 1, \T_CASE => 1, \T_CATCH => 1, \T_CLASS => 1,
\T_CLASS_C => 1, \T_CLONE => 1, \T_CONST => 1, \T_CONTINUE => 1, \T_CLASS_C => 1, \T_CLONE => 1, \T_CONST => 1, \T_CONTINUE => 1,
@ -92,23 +89,23 @@ class Tokenizer
\T_EXTENDS => 1, \T_FILE => 1, \T_FINAL => 1, \T_FOR => 1, \T_EXTENDS => 1, \T_FILE => 1, \T_FINAL => 1, \T_FOR => 1,
\T_FOREACH => 1, \T_FUNCTION => 1, \T_FUNC_C => 1, \T_GLOBAL => 1, \T_FOREACH => 1, \T_FUNCTION => 1, \T_FUNC_C => 1, \T_GLOBAL => 1,
\T_GOTO => 1, \T_HALT_COMPILER => 1, \T_IF => 1, \T_IMPLEMENTS => 1, \T_GOTO => 1, \T_HALT_COMPILER => 1, \T_IF => 1, \T_IMPLEMENTS => 1,
\T_INCLUDE => 1, \T_INCLUDE_ONCE => 1, \T_INSTANCEOF => 1, 341 /* T_INSTEADOF */ => 1, \T_INCLUDE => 1, \T_INCLUDE_ONCE => 1, \T_INSTANCEOF => 1, \T_INSTEADOF => 1,
\T_INTERFACE => 1, \T_ISSET => 1, \T_LINE => 1, \T_LIST => 1, \T_INTERFACE => 1, \T_ISSET => 1, \T_LINE => 1, \T_LIST => 1,
\T_LOGICAL_AND => 1, \T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_METHOD_C => 1, \T_LOGICAL_AND => 1, \T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_METHOD_C => 1,
\T_NAMESPACE => 1, \T_NS_C => 1, \T_NEW => 1, \T_PRINT => 1, \T_NAMESPACE => 1, \T_NS_C => 1, \T_NEW => 1, \T_PRINT => 1,
\T_PRIVATE => 1, \T_PUBLIC => 1, \T_PROTECTED => 1, \T_REQUIRE => 1, \T_PRIVATE => 1, \T_PUBLIC => 1, \T_PROTECTED => 1, \T_REQUIRE => 1,
\T_REQUIRE_ONCE => 1, \T_RETURN => 1, \T_RETURN => 1, \T_STRING => 1, \T_REQUIRE_ONCE => 1, \T_RETURN => 1, \T_STRING => 1,
\T_SWITCH => 1, \T_THROW => 1, 355 /* T_TRAIT */ => 1, 365 /* T_TRAIT_C */ => 1, \T_SWITCH => 1, \T_THROW => 1, \T_TRAIT => 1, \T_TRAIT_C => 1,
\T_TRY => 1, \T_UNSET => 1, \T_USE => 1, \T_VAR => 1, \T_TRY => 1, \T_UNSET => 1, \T_USE => 1, \T_VAR => 1,
\T_WHILE => 1, 267 /* T_YIELD */ => 1 \T_WHILE => 1, \T_YIELD => 1, \T_YIELD_FROM => 1
), ],
self::MACRO_INCDEC => array( self::MACRO_INCDEC => [
\T_INC => 1, \T_DEC => 1 \T_INC => 1, \T_DEC => 1
), ],
self::MACRO_UNARY => array( self::MACRO_UNARY => [
"!" => 1, "~" => 1, "-" => 1 "!" => 1, "~" => 1, "-" => 1
), ],
self::MACRO_BINARY => array( self::MACRO_BINARY => [
\T_BOOLEAN_AND => 1, \T_BOOLEAN_OR => 1, \T_IS_GREATER_OR_EQUAL => 1, \T_BOOLEAN_AND => 1, \T_BOOLEAN_OR => 1, \T_IS_GREATER_OR_EQUAL => 1,
\T_IS_EQUAL => 1, \T_IS_IDENTICAL => 1, \T_IS_NOT_EQUAL => 1, \T_IS_EQUAL => 1, \T_IS_IDENTICAL => 1, \T_IS_NOT_EQUAL => 1,
\T_IS_NOT_IDENTICAL => 1, \T_IS_SMALLER_OR_EQUAL => 1, \T_LOGICAL_AND => 1, \T_IS_NOT_IDENTICAL => 1, \T_IS_SMALLER_OR_EQUAL => 1, \T_LOGICAL_AND => 1,
@ -117,36 +114,36 @@ class Tokenizer
"*" => 1, "/" => 1, ">" => 1, "*" => 1, "/" => 1, ">" => 1,
"<" => 1, "^" => 1, "%" => 1, "<" => 1, "^" => 1, "%" => 1,
"&" => 1 "&" => 1
), ],
self::MACRO_BOOLEAN => array( self::MACRO_BOOLEAN => [
\T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1,
\T_BOOLEAN_AND => 1, \T_BOOLEAN_OR => 1, \T_BOOLEAN_AND => 1, \T_BOOLEAN_OR => 1,
\T_LOGICAL_AND => 1 \T_LOGICAL_AND => 1
), ],
self::MACRO_MATH => array( self::MACRO_MATH => [
"+" => 1, "-" => 1, "*" => 1, "+" => 1, "-" => 1, "*" => 1,
"/" => 1, "^" => 1, "%" => 1, "/" => 1, "^" => 1, "%" => 1,
"&" => 1, "|" => 1 "&" => 1, "|" => 1
), ],
self::MACRO_COND => array( self::MACRO_COND => [
\T_IS_EQUAL => 1, \T_IS_IDENTICAL => 1, ">" => 1, \T_IS_EQUAL => 1, \T_IS_IDENTICAL => 1, ">" => 1,
"<" => 1, \T_SL => 1, \T_SR => 1, "<" => 1, \T_SL => 1, \T_SR => 1,
\T_IS_NOT_EQUAL => 1, \T_IS_NOT_IDENTICAL => 1, \T_IS_SMALLER_OR_EQUAL => 1, \T_IS_NOT_EQUAL => 1, \T_IS_NOT_IDENTICAL => 1, \T_IS_SMALLER_OR_EQUAL => 1,
), ],
self::MACRO_EQUALS => array( self::MACRO_EQUALS => [
\T_AND_EQUAL => 1, \T_DIV_EQUAL => 1, \T_MINUS_EQUAL => 1, \T_AND_EQUAL => 1, \T_DIV_EQUAL => 1, \T_MINUS_EQUAL => 1,
\T_MOD_EQUAL => 1, \T_MUL_EQUAL => 1, \T_OR_EQUAL => 1, \T_MOD_EQUAL => 1, \T_MUL_EQUAL => 1, \T_OR_EQUAL => 1,
\T_PLUS_EQUAL => 1, \T_SL_EQUAL => 1, \T_SR_EQUAL => 1, \T_PLUS_EQUAL => 1, \T_SL_EQUAL => 1, \T_SR_EQUAL => 1,
\T_XOR_EQUAL => 1, '=' => 1, \T_XOR_EQUAL => 1, '=' => 1,
), ],
self::MACRO_SCALAR => array( self::MACRO_SCALAR => [
\T_LNUMBER => 1, \T_LNUMBER => 1,
\T_DNUMBER => 1, \T_DNUMBER => 1,
\T_CONSTANT_ENCAPSED_STRING => 1 \T_CONSTANT_ENCAPSED_STRING => 1
) ]
); ];
public static $description = array( public static array $description = [
self::MACRO_STRING => 'string', self::MACRO_STRING => 'string',
self::MACRO_INCDEC => 'increment/decrement operator', self::MACRO_INCDEC => 'increment/decrement operator',
self::MACRO_UNARY => 'unary operator', self::MACRO_UNARY => 'unary operator',
@ -156,26 +153,33 @@ class Tokenizer
self::MACRO_COND => 'conditional operator', self::MACRO_COND => 'conditional operator',
self::MACRO_EQUALS => 'equal operator', self::MACRO_EQUALS => 'equal operator',
self::MACRO_SCALAR => 'scalar value' self::MACRO_SCALAR => 'scalar value'
); ];
/** /**
* Special tokens * Special tokens
* @var array * @var array
*/ */
private static $spec = array( private static array $spec = [
'true' => 1, 'true' => 1,
'false' => 1, 'false' => 1,
'null' => 1, 'null' => 1,
'TRUE' => 1, 'TRUE' => 1,
'FALSE' => 1, 'FALSE' => 1,
'NULL' => 1 'NULL' => 1
); ];
private ?array $_next;
private ?array $_prev;
private ?array $_curr;
/** /**
* @param $query * @param string $query
*/ */
public function __construct($query) public function __construct(string $query)
{ {
$this->_curr = null;
$this->_next = null;
$this->_prev = null;
$tokens = array(-1 => array(\T_WHITESPACE, '', '', 1)); $tokens = array(-1 => array(\T_WHITESPACE, '', '', 1));
$_tokens = token_get_all("<?php " . $query); $_tokens = token_get_all("<?php " . $query);
$line = 1; $line = 1;
@ -195,7 +199,7 @@ class Tokenizer
$tokens[$i - 1][2] = $token[1]; $tokens[$i - 1][2] = $token[1];
continue; continue;
} elseif ($token[0] === \T_DNUMBER) { // fix .1 and 1. } elseif ($token[0] === \T_DNUMBER) { // fix .1 and 1.
if(strpos($token[1], '.') === 0) { if(str_starts_with($token[1], '.')) {
$tokens[] = array( $tokens[] = array(
'.', '.',
'.', '.',
@ -239,9 +243,9 @@ class Tokenizer
/** /**
* Is incomplete mean some string not closed * Is incomplete mean some string not closed
* *
* @return int * @return bool
*/ */
public function isIncomplete() public function isIncomplete(): bool
{ {
return ($this->quotes % 2) || ($this->tokens[$this->_max][0] === T_ENCAPSED_AND_WHITESPACE); return ($this->quotes % 2) || ($this->tokens[$this->_max][0] === T_ENCAPSED_AND_WHITESPACE);
} }
@ -252,9 +256,10 @@ class Tokenizer
* @link http://php.net/manual/en/iterator.current.php * @link http://php.net/manual/en/iterator.current.php
* @return mixed Can return any type. * @return mixed Can return any type.
*/ */
public function current() public function current(): mixed
{ {
return $this->curr ? $this->curr[1] : null; $curr = $this->currToken();
return $curr ? $curr[1] : null;
} }
/** /**
@ -263,13 +268,13 @@ class Tokenizer
* @link http://php.net/manual/en/iterator.next.php * @link http://php.net/manual/en/iterator.next.php
* @return Tokenizer * @return Tokenizer
*/ */
public function next() public function next(): static
{ {
if ($this->p > $this->_max) { if ($this->p > $this->_max) {
return $this; return $this;
} }
$this->p++; $this->p++;
unset($this->prev, $this->curr, $this->next); $this->cleanTokenCache();
return $this; return $this;
} }
@ -277,10 +282,10 @@ class Tokenizer
* Check token type. If token type is one of expected types return true. Otherwise return false * Check token type. If token type is one of expected types return true. Otherwise return false
* *
* @param array $expects * @param array $expects
* @param string|int $token * @param int|string $token
* @return bool * @return bool
*/ */
private function _valid($expects, $token) private function _valid(array $expects, int|string $token): bool
{ {
foreach ($expects as $expect) { foreach ($expects as $expect) {
if (is_string($expect) || $expect < 1000) { if (is_string($expect) || $expect < 1000) {
@ -300,13 +305,13 @@ class Tokenizer
/** /**
* If the next token is a valid one, move the position of cursor one step forward. Otherwise throws an exception. * If the next token is a valid one, move the position of cursor one step forward. Otherwise throws an exception.
* @param array $tokens * @param array $tokens
* @throws UnexpectedTokenException
* @return mixed * @return mixed
* @throws UnexpectedTokenException
*/ */
public function _next($tokens) public function _next(array $tokens): void
{ {
$this->next(); $this->next();
if (!$this->curr) { if (!$this->currToken()) {
throw new UnexpectedTokenException($this, $tokens); throw new UnexpectedTokenException($this, $tokens);
} }
if ($tokens) { if ($tokens) {
@ -323,7 +328,7 @@ class Tokenizer
* Fetch next specified token or throw an exception * Fetch next specified token or throw an exception
* @return mixed * @return mixed
*/ */
public function getNext( /*int|string $token1, int|string $token2, ... */) public function getNext( /*int|string $token1, int|string $token2, ... */): mixed
{ {
$this->_next(func_get_args()); $this->_next(func_get_args());
return $this->current(); return $this->current();
@ -333,9 +338,10 @@ class Tokenizer
* @param $token * @param $token
* @return bool * @return bool
*/ */
public function isNextToken($token) public function isNextToken($token): bool
{ {
return $this->next ? $this->next[1] == $token : false; $next = $this->nextToken();
return $next && $next[1] == $token;
} }
/** /**
@ -343,10 +349,11 @@ class Tokenizer
* @return mixed * @return mixed
* @throws UnexpectedTokenException * @throws UnexpectedTokenException
*/ */
public function getAndNext( /* $token1, ... */) public function getAndNext( /* $token1, ... */): mixed
{ {
if ($this->curr) { $curr = $this->currToken();
$cur = $this->curr[1]; if ($curr) {
$cur = $curr[1];
$this->next(); $this->next();
return $cur; return $cur;
} else { } else {
@ -359,9 +366,10 @@ class Tokenizer
* @param $token1 * @param $token1
* @return bool * @return bool
*/ */
public function isNext($token1 /*, ...*/) public function isNext($token1 /*, ...*/): bool
{ {
return $this->next && $this->_valid(func_get_args(), $this->next[0]); $next = $this->nextToken();
return $next && $this->_valid(func_get_args(), $next[0]);
} }
/** /**
@ -369,9 +377,10 @@ class Tokenizer
* @param $token1 * @param $token1
* @return bool * @return bool
*/ */
public function is($token1 /*, ...*/) public function is($token1 /*, ...*/): bool
{ {
return $this->curr && $this->_valid(func_get_args(), $this->curr[0]); $curr = $this->currToken();
return $curr && $this->_valid(func_get_args(), $curr[0]);
} }
/** /**
@ -379,22 +388,24 @@ class Tokenizer
* @param $token1 * @param $token1
* @return bool * @return bool
*/ */
public function isPrev($token1 /*, ...*/) public function isPrev($token1 /*, ...*/): bool
{ {
return $this->prev && $this->_valid(func_get_args(), $this->prev[0]); $prev = $this->prevToken();
return $prev && $this->_valid(func_get_args(), $prev[0]);
} }
/** /**
* Get specified token * Get specified token
* *
* @param string|int $token1 * @param int|string $token1
* @throws UnexpectedTokenException
* @return mixed * @return mixed
*@throws UnexpectedTokenException
*/ */
public function get($token1 /*, $token2 ...*/) public function get(int|string $token1 /*, $token2 ...*/): mixed
{ {
if ($this->curr && $this->_valid(func_get_args(), $this->curr[0])) { $curr = $this->currToken();
return $this->curr[1]; if ($curr && $this->_valid(func_get_args(), $curr[0])) {
return $curr[1];
} else { } else {
throw new UnexpectedTokenException($this, func_get_args()); throw new UnexpectedTokenException($this, func_get_args());
} }
@ -404,21 +415,21 @@ class Tokenizer
* Step back * Step back
* @return Tokenizer * @return Tokenizer
*/ */
public function back() public function back(): static
{ {
if ($this->p === 0) { if ($this->p === 0) {
return $this; return $this;
} }
$this->p--; $this->p--;
unset($this->prev, $this->curr, $this->next); $this->cleanTokenCache();
return $this; return $this;
} }
/** /**
* @param $token1 * @param int|string $token1
* @return bool * @return bool
*/ */
public function hasBackList($token1 /*, $token2 ...*/) public function hasBackList(int|string $token1 /*, $token2 ...*/): bool
{ {
$tokens = func_get_args(); $tokens = func_get_args();
$c = $this->p; $c = $this->p;
@ -431,27 +442,38 @@ class Tokenizer
return true; return true;
} }
/** public function prevToken(): mixed
* Lazy load properties
*
* @param string $key
* @return mixed
*/
public function __get($key)
{ {
switch ($key) { if ($this->_prev) {
case 'curr': return $this->_prev;
return $this->curr = ($this->p <= $this->_max) ? $this->tokens[$this->p] : null;
case 'next':
return $this->next = ($this->p + 1 <= $this->_max) ? $this->tokens[$this->p + 1] : null;
case 'prev':
return $this->prev = $this->p ? $this->tokens[$this->p - 1] : null;
default:
return $this->$key = null;
} }
return $this->_prev = $this->p ? $this->tokens[$this->p - 1] : null;
} }
public function count() public function currToken(): mixed
{
if ($this->_curr !== null) {
return $this->_curr;
}
return $this->_curr = ($this->p <= $this->_max) ? $this->tokens[$this->p] : null;
}
public function nextToken(): mixed
{
if ($this->_next) {
return $this->_next;
}
return $this->_next = ($this->p + 1 <= $this->_max) ? $this->tokens[$this->p + 1] : null;
}
protected function cleanTokenCache(): void
{
$this->_prev = null;
$this->_curr = null;
$this->_next = null;
}
public function count(): int
{ {
return $this->_max; return $this->_max;
} }
@ -460,9 +482,10 @@ class Tokenizer
* Return the key of the current element * Return the key of the current element
* @return mixed scalar on success, or null on failure. * @return mixed scalar on success, or null on failure.
*/ */
public function key() public function key(): mixed
{ {
return $this->curr ? $this->curr[0] : null; $curr = $this->currToken();
return $curr ? $curr[0] : null;
} }
/** /**
@ -470,18 +493,18 @@ class Tokenizer
* @return boolean The return value will be casted to boolean and then evaluated. * @return boolean The return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure. * Returns true on success or false on failure.
*/ */
public function valid() public function valid(): bool
{ {
return (bool)$this->curr; return (bool)$this->currToken();
} }
/** /**
* Get token name * Get token name
* @static * @static
* @param int|string $token * @param mixed $token
* @return string * @return string|null
*/ */
public static function getName($token) public static function getName(mixed $token): ?string
{ {
if (is_string($token)) { if (is_string($token)) {
return $token; return $token;
@ -500,10 +523,11 @@ class Tokenizer
* @throws UnexpectedTokenException * @throws UnexpectedTokenException
* @return Tokenizer * @return Tokenizer
*/ */
public function skip( /*$token1, $token2, ...*/) public function skip( /*$token1, $token2, ...*/): static
{ {
if (func_num_args()) { if (func_num_args()) {
if ($this->curr && $this->_valid(func_get_args(), $this->curr[0])) { $curr = $this->currToken();
if ($curr && $this->_valid(func_get_args(), $curr[0])) {
$this->next(); $this->next();
return $this; return $this;
} else { } else {
@ -521,9 +545,10 @@ class Tokenizer
* @param int|string $token1 * @param int|string $token1
* @return Tokenizer * @return Tokenizer
*/ */
public function skipIf($token1 /*, $token2, ...*/) public function skipIf(int|string $token1 /*, $token2, ...*/): static
{ {
if ($this->curr && $this->_valid(func_get_args(), $this->curr[0])) { $curr = $this->currToken();
if ($curr && $this->_valid(func_get_args(), $curr[0])) {
$this->next(); $this->next();
} }
return $this; return $this;
@ -536,9 +561,10 @@ class Tokenizer
* @return Tokenizer * @return Tokenizer
* @throws UnexpectedTokenException * @throws UnexpectedTokenException
*/ */
public function need($token1 /*, $token2, ...*/) public function need(int|string $token1 /*, $token2, ...*/): static
{ {
if ($this->curr && $this->_valid(func_get_args(), $this->curr[0])) { $curr = $this->currToken();
if ($curr && $this->_valid(func_get_args(), $curr[0])) {
return $this; return $this;
} else { } else {
throw new UnexpectedTokenException($this, func_get_args()); throw new UnexpectedTokenException($this, func_get_args());
@ -551,7 +577,7 @@ class Tokenizer
* @param int $after count tokens after current token * @param int $after count tokens after current token
* @return array * @return array
*/ */
public function getSnippet($before = 0, $after = 0) public function getSnippet(int $before = 0, int $after = 0): array
{ {
$from = 0; $from = 0;
$to = $this->p; $to = $this->p;
@ -594,7 +620,7 @@ class Tokenizer
* @param int $after * @param int $after
* @return string * @return string
*/ */
public function getSnippetAsString($before = 0, $after = 0) public function getSnippetAsString(int $before = 0, int $after = 0): string
{ {
$str = ""; $str = "";
foreach ($this->getSnippet($before, $after) as $token) { foreach ($this->getSnippet($before, $after) as $token) {
@ -607,7 +633,7 @@ class Tokenizer
* Check if current is special value: true, TRUE, false, FALSE, null, NULL * Check if current is special value: true, TRUE, false, FALSE, null, NULL
* @return bool * @return bool
*/ */
public function isSpecialVal() public function isSpecialVal(): bool
{ {
return isset(self::$spec[$this->current()]); return isset(self::$spec[$this->current()]);
} }
@ -616,7 +642,7 @@ class Tokenizer
* Check if the token is last * Check if the token is last
* @return bool * @return bool
*/ */
public function isLast() public function isLast(): bool
{ {
return $this->p === $this->_max; return $this->p === $this->_max;
} }
@ -624,10 +650,10 @@ class Tokenizer
/** /**
* Move pointer to the end * Move pointer to the end
*/ */
public function end() public function end(): static
{ {
$this->p = $this->_max; $this->p = $this->_max;
unset($this->prev, $this->curr, $this->next); $this->cleanTokenCache();
return $this; return $this;
} }
@ -635,23 +661,26 @@ class Tokenizer
* Return line number of the current token * Return line number of the current token
* @return mixed * @return mixed
*/ */
public function getLine() public function getLine(): mixed
{ {
return $this->curr ? $this->curr[3] : $this->_last_no; $curr = $this->currToken();
return $curr ? $curr[3] : $this->_last_no;
} }
/** /**
* Is current token whitespaced, means previous token has whitespace characters * Is current token whitespaced, means previous token has whitespace characters
* @return bool * @return bool
*/ */
public function isWhiteSpaced() public function isWhiteSpaced(): bool
{ {
return $this->prev ? (bool)$this->prev[2] : false; $prev = $this->prevToken();
return $prev && $prev[2];
} }
public function getWhitespace() public function getWhitespace()
{ {
return $this->curr ? $this->curr[2] : false; $curr = $this->currToken();
return $curr ? $curr[2] : false;
} }
/** /**
@ -659,10 +688,10 @@ class Tokenizer
* @param int $p * @param int $p
* @return $this * @return $this
*/ */
public function seek($p) public function seek(int $p): static
{ {
$this->p = $p; $this->p = $p;
unset($this->prev, $this->curr, $this->next); $this->cleanTokenCache();
return $this; return $this;
} }
} }

View File

@ -53,7 +53,7 @@ class TestCase extends \PHPUnit\Framework\TestCase
return FENOM_RESOURCES . '/compile'; return FENOM_RESOURCES . '/compile';
} }
public function setUp() public function setUp(): void
{ {
if (!file_exists($this->getCompilePath())) { if (!file_exists($this->getCompilePath())) {
mkdir($this->getCompilePath(), 0777, true); mkdir($this->getCompilePath(), 0777, true);
@ -89,7 +89,7 @@ class TestCase extends \PHPUnit\Framework\TestCase
public static function inlineFunction($params) public static function inlineFunction($params)
{ {
return isset($params["text"]) ? $params["text"] : ""; return $params["text"] ?? "";
} }
public static function blockFunction($params, $text) public static function blockFunction($params, $text)
@ -97,7 +97,7 @@ class TestCase extends \PHPUnit\Framework\TestCase
return $text; return $text;
} }
public static function setUpBeforeClass() public static function setUpBeforeClass(): void
{ {
if (!file_exists(FENOM_RESOURCES . '/template')) { if (!file_exists(FENOM_RESOURCES . '/template')) {
mkdir(FENOM_RESOURCES . '/template', 0777, true); mkdir(FENOM_RESOURCES . '/template', 0777, true);

View File

@ -1,11 +1,7 @@
<?php <?php
require(__DIR__ . "/../src/Fenom.php"); require(__DIR__ . "/../src/Fenom.php");
Fenom::registerAutoload(); //Fenom::registerAutoload();
if(!class_exists('\PHPUnit_Framework_TestCase') && class_exists('\PHPUnit\Framework\TestCase')) {
class_alias('\PHPUnit\Framework\TestCase', '\PHPUnit_Framework_TestCase');
}
define('FENOM_RESOURCES', __DIR__ . "/resources"); define('FENOM_RESOURCES', __DIR__ . "/resources");

View File

@ -45,7 +45,7 @@ class TokenizerTest extends TestCase
' ', ' ',
1 1
), ),
$tokens->curr $tokens->currToken()
); );
$this->assertSame("resolve", $tokens->getNext($tokens::MACRO_UNARY, T_STRING)); $this->assertSame("resolve", $tokens->getNext($tokens::MACRO_UNARY, T_STRING));
@ -106,7 +106,6 @@ class TokenizerTest extends TestCase
$this->assertSame($tokens, $tokens->next()); $this->assertSame($tokens, $tokens->next());
$tokens->p = -1000; $tokens->p = -1000;
$this->assertSame($tokens, $tokens->back()); $this->assertSame($tokens, $tokens->back());
$this->assertNull($tokens->undef);
} }
public function testFixFloats() { public function testFixFloats() {