GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( ca892c...ef0aaf )
by Zordius
03:24
created

Compiler::blockEnd()   B

Complexity

Conditions 11
Paths 21

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 11.2682

Importance

Changes 0
Metric Value
dl 0
loc 32
ccs 20
cts 23
cp 0.8696
rs 7.3166
c 0
b 0
f 0
cc 11
nc 21
nop 3
crap 11.2682

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
4
MIT License
5
Copyright 2013-2018 Zordius Chen. All Rights Reserved.
6
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9
10
Origin: https://github.com/zordius/lightncandy
11
*/
12
13
/**
14
 * file of LightnCandy Compiler
15
 *
16
 * @package    LightnCandy
17
 * @author     Zordius <[email protected]>
18
 */
19
20
namespace LightnCandy;
21
22
use \LightnCandy\Validator;
23
use \LightnCandy\Token;
24
use \LightnCandy\Expression;
25
use \LightnCandy\Parser;
26
27
/**
28
 * LightnCandy Compiler
29
 */
30
class Compiler extends Validator
31
{
32
    public static $lastParsed;
33
34
    /**
35
     * Compile template into PHP code
36
     *
37
     * @param array<string,array|string|integer> $context Current context
38
     * @param string $template handlebars template
39
     *
40
     * @return string|null generated PHP code
41
     */
42 792
    public static function compileTemplate(&$context, $template) {
43 792
        array_unshift($context['parsed'], array());
44 792
        Validator::verify($context, $template);
45 792
        static::$lastParsed = $context['parsed'];
46
47 792
        if (count($context['error'])) {
48 78
            return;
49
        }
50
51 715
        Parser::setDelimiter($context);
52
53 715
        $context['compile'] = true;
54
55
        // Handle dynamic partials
56 715
        Partial::handleDynamic($context);
57
58
        // Do PHP code generation.
59 715
        $code = '';
60 715
        foreach ($context['parsed'][0] as $info) {
61 715
            if (is_array($info)) {
62 674
                $context['tokens']['current']++;
63 674
                $code .= "'" . static::compileToken($context, $info) . "'";
64
            } else {
65 501
                $code .= $info;
66
            }
67
        }
68
69 715
        array_shift($context['parsed']);
70
71 715
        return $code;
72
    }
73
74
    /**
75
     * Compose LightnCandy render codes for include()
76
     *
77
     * @param array<string,array|string|integer> $context Current context
78
     * @param string $code generated PHP code
79
     *
80
     * @return string Composed PHP code
81
     */
82 714
    public static function composePHPRender($context, $code) {
83 714
        $flagJStrue = Expression::boolString($context['flags']['jstrue']);
84 714
        $flagJSObj = Expression::boolString($context['flags']['jsobj']);
85 714
        $flagJSLen = Expression::boolString($context['flags']['jslen']);
86 714
        $flagSPVar = Expression::boolString($context['flags']['spvar']);
87 714
        $flagProp = Expression::boolString($context['flags']['prop']);
88 714
        $flagMethod = Expression::boolString($context['flags']['method']);
89 714
        $flagLambda = Expression::boolString($context['flags']['lambda']);
90 714
        $flagMustlok = Expression::boolString($context['flags']['mustlok']);
91 714
        $flagMustlam = Expression::boolString($context['flags']['mustlam']);
92 714
        $flagMustsec = Expression::boolString($context['flags']['mustsec']);
93 714
        $flagEcho = Expression::boolString($context['flags']['echo']);
94 714
        $flagPartNC = Expression::boolString($context['flags']['partnc']);
95 714
        $flagKnownHlp = Expression::boolString($context['flags']['knohlp']);
96
97 714
        $constants = Exporter::constants($context);
98 714
        $helpers = Exporter::helpers($context);
99 714
        $partials = implode(",\n", $context['partialCode']);
100 714
        $debug = Runtime::DEBUG_ERROR_LOG;
101 714
        $use = $context['flags']['standalone'] ? Exporter::runtime($context) : "use {$context['runtime']} as {$context['runtimealias']};";
102 714
        $stringObject = $context['flags']['method'] || $context['flags']['prop'] ? Exporter::stringobject($context) : '';
103 714
        $safeString = (($context['usedFeature']['enc'] > 0) && ($context['flags']['standalone'] === 0)) ? "use {$context['safestring']} as SafeString;" : '';
104 714
        $exportSafeString = (($context['usedFeature']['enc'] > 0) && ($context['flags']['standalone'] >0)) ? Exporter::safestring($context) : '';
105
        // Return generated PHP code string.
106
        return <<<VAREND
107 714
$stringObject{$safeString}{$use}{$exportSafeString}return function (\$in = null, \$options = null) {
108 714
    \$helpers = $helpers;
109 714
    \$partials = array($partials);
110
    \$cx = array(
111
        'flags' => array(
112 714
            'jstrue' => $flagJStrue,
113 714
            'jsobj' => $flagJSObj,
114 714
            'jslen' => $flagJSLen,
115 714
            'spvar' => $flagSPVar,
116 714
            'prop' => $flagProp,
117 714
            'method' => $flagMethod,
118 714
            'lambda' => $flagLambda,
119 714
            'mustlok' => $flagMustlok,
120 714
            'mustlam' => $flagMustlam,
121 714
            'mustsec' => $flagMustsec,
122 714
            'echo' => $flagEcho,
123 714
            'partnc' => $flagPartNC,
124 714
            'knohlp' => $flagKnownHlp,
125 714
            'debug' => isset(\$options['debug']) ? \$options['debug'] : $debug,
126
        ),
127 714
        'constants' => $constants,
128
        'helpers' => isset(\$options['helpers']) ? array_merge(\$helpers, \$options['helpers']) : \$helpers,
129
        'partials' => isset(\$options['partials']) ? array_merge(\$partials, \$options['partials']) : \$partials,
130
        'scopes' => array(),
131
        'sp_vars' => isset(\$options['data']) ? array_merge(array('root' => \$in), \$options['data']) : array('root' => \$in),
132
        'blparam' => array(),
133
        'partialid' => 0,
134 714
        'runtime' => '{$context['runtime']}',
135
    );
136 714
    {$context['renderex']}
137 714
    {$context['ops']['array_check']}
138 714
    {$context['ops']['op_start']}'$code'{$context['ops']['op_end']}
139
};
140
VAREND
141
        ;
142
    }
143
144
    /**
145
     * Get function name for standalone or none standalone template.
146
     *
147
     * @param array<string,array|string|integer> $context Current context of compiler progress.
148
     * @param string $name base function name
149
     * @param string $tag original handlabars tag for debug
150
     *
151
     * @return string compiled Function name
152
     *
153
     * @expect 'LR::test(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime', 'runtimealias' => 'LR'), 'test', ''
154
     * @expect 'LL::test2(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime', 'runtimealias' => 'LL'), 'test2', ''
155
     * @expect "lala_abctest3(" when input array('flags' => array('standalone' => 1, 'debug' => 0), 'runtime' => 'Runtime', 'runtimealias' => 0, 'funcprefix' => 'lala_abc'), 'test3', ''
156
     * @expect 'RR::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1), 'runtime' => 'Runtime', 'runtimealias' => 'RR', 'funcprefix' => 'haha456'), 'test', 'abc'
157
     */
158 646
    protected static function getFuncName(&$context, $name, $tag) {
159 646
        static::addUsageCount($context, 'runtime', $name);
160
161 646
        if ($context['flags']['debug'] && ($name != 'miss')) {
162 10
            $dbg = "'$tag', '$name', ";
163 10
            $name = 'debug';
164 10
            static::addUsageCount($context, 'runtime', 'debug');
165
        } else {
166 644
            $dbg = '';
167
        }
168
169 646
        return $context['flags']['standalone'] ? "{$context['funcprefix']}$name($dbg" : "{$context['runtimealias']}::$name($dbg";
170
    }
171
172
    /**
173
     * Get string presentation of variables
174
     *
175
     * @param array<string,array|string|integer> $context current compile context
176
     * @param array<array> $vn variable name array.
177
     * @param array<string>|null $blockParams block param list
178
     *
179
     * @return array<string|array> variable names
180
     *
181
     * @expect array('array(array($in),array())', array('this')) when input array('flags'=>array('spvar'=>true)), array(null)
182
     * @expect array('array(array($in,$in),array())', array('this', 'this')) when input array('flags'=>array('spvar'=>true)), array(null, null)
183
     * @expect array('array(array(),array(\'a\'=>$in))', array('this')) when input array('flags'=>array('spvar'=>true)), array('a' => null)
184
     */
185 294
    protected static function getVariableNames(&$context, $vn, $blockParams = null) {
186 294
        $vars = array(array(), array());
187 294
        $exps = array();
188 294
        foreach ($vn as $i => $v) {
189 250
            $V = static::getVariableNameOrSubExpression($context, $v);
190 250
            if (is_string($i)) {
191 38
                $vars[1][] = "'$i'=>{$V[0]}";
192
            } else {
193 235
                $vars[0][] = $V[0];
194
            }
195 250
            $exps[] = $V[1];
196
        }
197 294
        $bp = $blockParams ? (',array(' . Expression::listString($blockParams) . ')') : '';
198 294
        return array('array(array(' . implode(',', $vars[0]) . '),array(' . implode(',', $vars[1]) . ")$bp)", $exps);
199
    }
200
201
    /**
202
     * Get string presentation of a sub expression
203
     *
204
     * @param array<string,array|string|integer> $context current compile context
205
     * @param array<boolean|integer|string|array> $vars parsed arguments list
206
     *
207
     * @return array<string> code representing passed expression
208
     */
209 46
    public static function compileSubExpression(&$context, $vars) {
210 46
        $ret = static::customHelper($context, $vars, true, true, true);
211
212 46
        if (($ret === null) && $context['flags']['lambda']) {
213 4
            $ret = static::compileVariable($context, $vars, true, true);
214
        }
215
216 46
        return array($ret ? $ret : '', 'FIXME: $subExpression');
217
    }
218
219
    /**
220
     * Get string presentation of a subexpression or a variable
221
     *
222
     * @param array<array|string|integer> $context current compile context
223
     * @param array<array|string|integer> $var variable parsed path
224
     *
225
     * @return array<string> variable names
226
     */
227 415
    protected static function getVariableNameOrSubExpression(&$context, $var) {
228 415
        return Parser::isSubExp($var) ? static::compileSubExpression($context, $var[1]) : static::getVariableName($context, $var);
229
    }
230
231
    /**
232
     * Get string presentation of a variable
233
     *
234
     * @param array<array|string|integer> $var variable parsed path
235
     * @param array<array|string|integer> $context current compile context
236
     * @param array<string>|null $lookup extra lookup string as valid PHP variable name
237
     *
238
     * @return array<string> variable names
239
     *
240
     * @expect array('$in', 'this') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(null)
241
     * @expect array('(($inary && isset($in[\'true\'])) ? $in[\'true\'] : null)', '[true]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('true')
242
     * @expect array('(($inary && isset($in[\'false\'])) ? $in[\'false\'] : null)', '[false]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('false')
243
     * @expect array('true', 'true') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'true')
244
     * @expect array('false', 'false') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'false')
245
     * @expect array('(($inary && isset($in[\'2\'])) ? $in[\'2\'] : null)', '[2]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('2')
246
     * @expect array('2', '2') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0)), array(-1, '2')
247
     * @expect array('(($inary && isset($in[\'@index\'])) ? $in[\'@index\'] : null)', '[@index]') when input array('flags'=>array('spvar'=>false,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('@index')
248
     * @expect array("(isset(\$cx['sp_vars']['index']) ? \$cx['sp_vars']['index'] : null)", '@[index]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('@index')
249
     * @expect array("(isset(\$cx['sp_vars']['key']) ? \$cx['sp_vars']['key'] : null)", '@[key]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('@key')
250
     * @expect array("(isset(\$cx['sp_vars']['first']) ? \$cx['sp_vars']['first'] : null)", '@[first]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('@first')
251
     * @expect array("(isset(\$cx['sp_vars']['last']) ? \$cx['sp_vars']['last'] : null)", '@[last]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('@last')
252
     * @expect array('(($inary && isset($in[\'"a"\'])) ? $in[\'"a"\'] : null)', '["a"]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('"a"')
253
     * @expect array('"a"', '"a"') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, '"a"')
254
     * @expect array('(($inary && isset($in[\'a\'])) ? $in[\'a\'] : null)', '[a]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array('a')
255
     * @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-1]) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-1]) && isset($cx[\'scopes\'][count($cx[\'scopes\'])-1][\'a\'])) ? $cx[\'scopes\'][count($cx[\'scopes\'])-1][\'a\'] : null)', '../[a]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array(1,'a')
256
     * @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-3]) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-3]) && isset($cx[\'scopes\'][count($cx[\'scopes\'])-3][\'a\'])) ? $cx[\'scopes\'][count($cx[\'scopes\'])-3][\'a\'] : null)', '../../../[a]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array(3,'a')
257
     * @expect array('(($inary && isset($in[\'id\'])) ? $in[\'id\'] : null)', 'this.[id]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0)), array(null, 'id')
258
     * @expect array('LR::v($cx, $in, isset($in) ? $in : null, array(\'id\'))', 'this.[id]') when input array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0,'lambda'=>0,'jslen'=>0,'standalone'=>0), 'runtime' => 'Runtime', 'runtimealias' => 'LR'), array(null, 'id')
259
     */
260 639
    protected static function getVariableName(&$context, $var, $lookup = null, $args = null) {
261 639
        if (isset($var[0]) && ($var[0] === Parser::LITERAL)) {
262 93
            if ($var[1] === "undefined") {
263 2
                $var[1] = "null";
264
            }
265 93
            return array($var[1], preg_replace('/\'(.*)\'/', '$1', $var[1]));
266
        }
267
268 596
        list($levels, $spvar, $var) = Expression::analyze($context, $var);
269 596
        $exp = Expression::toString($levels, $spvar, $var);
270 596
        $base = $spvar ? "\$cx['sp_vars']" : '$in';
271
272
        // change base when trace to parent
273 596
        if ($levels > 0) {
274 41
            if ($spvar) {
275 2
                $base .= str_repeat("['_parent']", $levels);
276
            } else {
277 39
                $base = "\$cx['scopes'][count(\$cx['scopes'])-$levels]";
278
            }
279
        }
280
281 596
        if ((empty($var) || (count($var) == 0) || (($var[0] === null) && (count($var) == 1))) && ($lookup === null)) {
282 164
            return array($base, $exp);
283
        }
284
285 524
        if ((count($var) > 0) && ($var[0] === null)) {
286 1
            array_shift($var);
287
        }
288
289
        // To support recursive context lookup, instance properties + methods and lambdas
290
        // the only way is using slower rendering time variable resolver.
291 524
        if ($context['flags']['prop'] || $context['flags']['method'] || $context['flags']['mustlok'] || $context['flags']['mustlam'] || $context['flags']['lambda']) {
292 389
            $L = Expression::listString($var);
293 389
            $L = ($L === '') ? array() : array($L);
294 389
            if ($lookup) {
295 3
                $L[] = $lookup[0];
296
            }
297 389
            $A = $args ? ",$args[0]" : '';
298 389
            $E = $args ? ' ' . implode(' ', $args[1]) : '';
299 389
            return array(static::getFuncName($context, 'v', $exp) . "\$cx, \$in, isset($base) ? $base : null, array(" . implode($L, ',') . ")$A)", $lookup ? "lookup $exp $lookup[1]" : "$exp$E");
300
        }
301
302 136
        $n = Expression::arrayString($var);
303 136
        $k = array_pop($var);
304 136
        $L = $lookup ? "[{$lookup[0]}]" : '';
305 136
        $p = $lookup ? $n : (count($var) ? Expression::arrayString($var) : '');
306
307 136
        $checks = array();
308 136
        if ($levels > 0) {
309 11
            $checks[] = "isset($base)";
310
        }
311 136
        if (!$spvar) {
312 132
            if (($levels === 0) && $p) {
313 15
                $checks[] = "isset($base$p)";
314
            }
315 132
            $checks[] = ("$base$p" == '$in') ? '$inary' : "is_array($base$p)";
316
        }
317 136
        $checks[] = "isset($base$n$L)";
318 136
        $check = ((count($checks) > 1) ? '(' : '') . implode(' && ', $checks) . ((count($checks) > 1) ? ')' : '');
319
320 136
        $lenStart = '';
321 136
        $lenEnd = '';
322
323 136
        if ($context['flags']['jslen']) {
324 54
            if (($lookup === null) && ($k === 'length')) {
325 1
                array_pop($checks);
326 1
                $lenStart = '(' . ((count($checks) > 1) ? '(' : '') . implode(' && ', $checks) . ((count($checks) > 1) ? ')' : '') . " ? count($base" . Expression::arrayString($var) . ') : ';
327 1
                $lenEnd = ')';
328
            }
329
        }
330
331 136
        return array("($check ? $base$n$L : $lenStart" . ($context['flags']['debug'] ? (static::getFuncName($context, 'miss', '') . "\$cx, '$exp')") : 'null' ) . ")$lenEnd", $lookup ? "lookup $exp $lookup[1]" : $exp);
332
    }
333
334
    /**
335
     * Return compiled PHP code for a handlebars token
336
     *
337
     * @param array<string,array|string|integer> $context current compile context
338
     * @param array<string,array|boolean> $info parsed information
339
     *
340
     * @return string Return compiled code segment for the token
341
     */
342 674
    protected static function compileToken(&$context, $info) {
343 674
        list($raw, $vars, $token, $indent) = $info;
344
345 674
        $context['tokens']['partialind'] = $indent;
346 674
        $context['currentToken'] = $token;
347
348 674
        if ($ret = static::operator($token[Token::POS_OP], $context, $vars)) {
349 421
            return $ret;
350
        }
351
352 515
        if (isset($vars[0][0])) {
353 481
            if ($ret = static::customHelper($context, $vars, $raw, true)) {
354 121
                return static::compileOutput($context, $ret, 'FIXME: helper', $raw, false);
355
            }
356 367
            if ($context['flags']['else'] && ($vars[0][0] === 'else')) {
357 35
                return static::doElse($context, $vars);
358
            }
359 343
            if ($vars[0][0] === 'lookup') {
360 5
                return static::compileLookup($context, $vars, $raw);
361
            }
362 338
            if ($vars[0][0] === 'log') {
363 2
                return static::compileLog($context, $vars, $raw);
364
            }
365
        }
366
367 378
        return static::compileVariable($context, $vars, $raw, false);
368
    }
369
370
    /**
371
     * handle partial
372
     *
373
     * @param array<string,array|string|integer> $context current compile context
374
     * @param array<boolean|integer|string|array> $vars parsed arguments list
375
     *
376
     * @return string Return compiled code segment for the partial
377
     */
378 110
    public static function partial(&$context, $vars) {
379 110
        Parser::getBlockParams($vars);
380 110
        $pid = Parser::getPartialBlock($vars);
381 110
        $p = array_shift($vars);
382 110
        if ($context['flags']['runpart']) {
383 100
            if (!isset($vars[0])) {
384 93
                $vars[0] = $context['flags']['partnc'] ? array(0, 'null') : array();
385
            }
386 100
            $v = static::getVariableNames($context, $vars);
387 100
            $tag = ">$p[0] " .implode(' ', $v[1]);
388 100
            if (Parser::isSubExp($p)) {
389 6
                list($p) = static::compileSubExpression($context, $p[1]);
390
            } else {
391 94
                $p = "'$p[0]'";
392
            }
393 100
            $sp = $context['tokens']['partialind'] ? ", '{$context['tokens']['partialind']}'" : '';
394 100
            return $context['ops']['seperator'] . static::getFuncName($context, 'p', $tag) . "\$cx, $p, $v[0],$pid$sp){$context['ops']['seperator']}";
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $context['ops']['...['ops']['seperator']}"; (string) is incompatible with the return type of the parent method LightnCandy\Validator::partial of type integer|double|boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
395
        }
396 10
        return isset($context['usedPartial'][$p[0]]) ? "{$context['ops']['seperator']}'" . Partial::compileStatic($context, $p[0]) . "'{$context['ops']['seperator']}" : $context['ops']['seperator'];
397
    }
398
399
    /**
400
     * handle inline partial
401
     *
402
     * @param array<string,array|string|integer> $context current compile context
403
     * @param array<boolean|integer|string|array> $vars parsed arguments list
404
     *
405
     * @return string Return compiled code segment for the partial
406
     */
407 11
    public static function inline(&$context, $vars) {
408 11
        Parser::getBlockParams($vars);
409 11
        list($code) = array_shift($vars);
410 11
        $p = array_shift($vars);
411 11
        if (!isset($vars[0])) {
412 11
            $vars[0] = $context['flags']['partnc'] ? array(0, 'null') : array();
413
        }
414 11
        $v = static::getVariableNames($context, $vars);
415 11
        $tag = ">*inline $p[0]" .implode(' ', $v[1]);
416 11
        return $context['ops']['seperator'] . static::getFuncName($context, 'in', $tag) . "\$cx, '{$p[0]}', $code){$context['ops']['seperator']}";
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $context['ops']['...['ops']['seperator']}"; (string) is incompatible with the return type of the parent method LightnCandy\Validator::inline of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
417
    }
418
419
    /**
420
     * Return compiled PHP code for a handlebars inverted section begin token
421
     *
422
     * @param array<string,array|string|integer> $context current compile context
423
     * @param array<boolean|integer|string|array> $vars parsed arguments list
424
     *
425
     * @return string Return compiled code segment for the token
426
     */
427 38
    protected static function invertedSection(&$context, $vars) {
428 38
        $v = static::getVariableName($context, $vars[0]);
429 38
        return "{$context['ops']['cnd_start']}(" . static::getFuncName($context, 'isec', '^' . $v[1]) . "\$cx, {$v[0]})){$context['ops']['cnd_then']}";
430
    }
431
432
    /**
433
     * Return compiled PHP code for a handlebars block custom helper begin token
434
     *
435
     * @param array<string,array|string|integer> $context current compile context
436
     * @param array<boolean|integer|string|array> $vars parsed arguments list
437
     * @param boolean $inverted the logic will be inverted
438
     *
439
     * @return string Return compiled code segment for the token
440
     */
441 64
    protected static function blockCustomHelper(&$context, $vars, $inverted = false) {
442 64
        $bp = Parser::getBlockParams($vars);
443 64
        $ch = array_shift($vars);
444 64
        $inverted = $inverted ? 'true' : 'false';
445 64
        static::addUsageCount($context, 'helpers', $ch[0]);
446 64
        $v = static::getVariableNames($context, $vars, $bp);
447
448 64
        return $context['ops']['seperator'] . static::getFuncName($context, 'hbbch', ($inverted ? '^' : '#') . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, \$in, $inverted, function(\$cx, \$in) {{$context['ops']['array_check']}{$context['ops']['f_start']}";
449
    }
450
451
    /**
452
     * Return compiled PHP code for a handlebars block end token
453
     *
454
     * @param array<string,array|string|integer> $context current compile context
455
     * @param array<boolean|integer|string|array> $vars parsed arguments list
456
     * @param string|null $matchop should also match to this operator
457
     *
458
     * @return string Return compiled code segment for the token
459
     */
460 343
    protected static function blockEnd(&$context, &$vars, $matchop = NULL) {
461 343
        $pop = $context['stack'][count($context['stack']) - 1];
462
463 343
        switch (isset($context['helpers'][$context['currentToken'][Token::POS_INNERTAG]]) ? 'skip' : $context['currentToken'][Token::POS_INNERTAG]) {
464 343
            case 'if':
465 286
            case 'unless':
466 83
                if ($pop === ':') {
467 30
                    array_pop($context['stack']);
468 30
                    return "{$context['ops']['cnd_end']}";
469
                }
470 57
                if (!$context['flags']['nohbh']) {
471 55
                    return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
472
                }
473 2
                break;
474 282
            case 'with':
475 33
                if (!$context['flags']['nohbh']) {
476 32
                    return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
477
                }
478
        }
479
480 259
        if ($pop === ':') {
481
            array_pop($context['stack']);
482
            return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
483
        }
484
485 259
        switch($pop) {
486 259
            case '#':
487 234
                return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
488 33
            case '^':
489 33
                return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
490
        }
491
    }
492
493
    /**
494
     * Return compiled PHP code for a handlebars block begin token
495
     *
496
     * @param array<string,array|string|integer> $context current compile context
497
     * @param array<boolean|integer|string|array> $vars parsed arguments list
498
     *
499
     * @return string Return compiled code segment for the token
500
     */
501 258
    protected static function blockBegin(&$context, $vars) {
502 258
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($context, $vars[1]) : array(null, array());
503 258
        if (!$context['flags']['nohbh']) {
504 219
            switch (isset($vars[0][0]) ? $vars[0][0] : null) {
505 219
                case 'if':
506 73
                    $includeZero = (isset($vars['includeZero'][1]) && $vars['includeZero'][1]) ? 'true' : 'false';
507 73
                    return "{$context['ops']['cnd_start']}(" . static::getFuncName($context, 'ifvar', $v[1]) . "\$cx, {$v[0]}, {$includeZero})){$context['ops']['cnd_then']}";
0 ignored issues
show
Bug introduced by
It seems like $v[1] can also be of type array; however, LightnCandy\Compiler::getFuncName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug Best Practice introduced by
The return type of return "{$context['ops']...t['ops']['cnd_then']}"; (string) is incompatible with the return type of the parent method LightnCandy\Validator::blockBegin of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
508 165
                case 'unless':
509 4
                    return "{$context['ops']['cnd_start']}(!" . static::getFuncName($context, 'ifvar', $v[1]) . "\$cx, {$v[0]}, false)){$context['ops']['cnd_then']}";
0 ignored issues
show
Bug introduced by
It seems like $v[1] can also be of type array; however, LightnCandy\Compiler::getFuncName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug Best Practice introduced by
The return type of return "{$context['ops']...t['ops']['cnd_then']}"; (string) is incompatible with the return type of the parent method LightnCandy\Validator::blockBegin of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
510 162
                case 'each':
511 53
                    return static::section($context, $vars, true);
0 ignored issues
show
Bug Compatibility introduced by
The expression static::section($context, $vars, true); of type string|null adds the type string to the return on line 511 which is incompatible with the return type of the parent method LightnCandy\Validator::blockBegin of type boolean.
Loading history...
512 112
                case 'with':
513 32
                    if ($r = static::with($context, $vars)) {
514 32
                        return $r;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $r; (string) is incompatible with the return type of the parent method LightnCandy\Validator::blockBegin of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
515
                    }
516
            }
517
        }
518
519 121
        return static::section($context, $vars);
0 ignored issues
show
Bug Compatibility introduced by
The expression static::section($context, $vars); of type string|null adds the type string to the return on line 519 which is incompatible with the return type of the parent method LightnCandy\Validator::blockBegin of type boolean.
Loading history...
520
    }
521
522
    /**
523
     * compile {{#foo}} token
524
     *
525
     * @param array<string,array|string|integer> $context current compile context
526
     * @param array<boolean|integer|string|array> $vars parsed arguments list
527
     * @param boolean $isEach the section is #each
528
     *
529
     * @return string|null Return compiled code segment for the token
530
     */
531 174
    protected static function section(&$context, $vars, $isEach = false) {
532 174
        $bs = 'null';
533 174
        $be = '';
534 174
        if ($isEach) {
535 53
            $bp = Parser::getBlockParams($vars);
536 53
            $bs = $bp ? ('array(' . Expression::listString($bp) . ')') : 'null';
537 53
            $be = $bp ? (' as |' . implode($bp, ' ') . '|') : '';
538 53
            array_shift($vars);
539
        }
540 174
        if ($context['flags']['lambda'] && !$isEach) {
541 69
            $V = array_shift($vars);
542 69
            $v = static::getVariableName($context, $V, null, count($vars) ? static::getVariableNames($context, $vars) : array('0',array('')));
543
        } else {
544 105
            $v = static::getVariableNameOrSubExpression($context, $vars[0]);
545
        }
546 174
        $each = $isEach ? 'true' : 'false';
547 174
        return $context['ops']['seperator'] . static::getFuncName($context, 'sec', ($isEach ? 'each ' : '') . $v[1] . $be) . "\$cx, {$v[0]}, $bs, \$in, $each, function(\$cx, \$in) {{$context['ops']['array_check']}{$context['ops']['f_start']}";
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $context['ops']['...xt['ops']['f_start']}"; (string) is incompatible with the return type of the parent method LightnCandy\Validator::section of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
548
    }
549
550
    /**
551
     * compile {{with}} token
552
     *
553
     * @param array<string,array|string|integer> $context current compile context
554
     * @param array<boolean|integer|string|array> $vars parsed arguments list
555
     *
556
     * @return string|null Return compiled code segment for the token
557
     */
558 32
    protected static function with(&$context, $vars) {
559 32
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($context, $vars[1]) : array(null, array());
560 32
        $bp = Parser::getBlockParams($vars);
561 32
        $bs = $bp ? ('array(' . Expression::listString($bp) . ')') : 'null';
562 32
        $be = $bp ? " as |$bp[0]|" : '';
563 32
        return $context['ops']['seperator'] . static::getFuncName($context, 'wi', 'with ' . $v[1] . $be) . "\$cx, {$v[0]}, $bs, \$in, function(\$cx, \$in) {{$context['ops']['array_check']}{$context['ops']['f_start']}";
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $context['ops']['...xt['ops']['f_start']}"; (string) is incompatible with the return type of the parent method LightnCandy\Validator::with of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
564
    }
565
566
    /**
567
     * Return compiled PHP code for a handlebars custom helper token
568
     *
569
     * @param array<string,array|string|integer> $context current compile context
570
     * @param array<boolean|integer|string|array> $vars parsed arguments list
571
     * @param boolean $raw is this {{{ token or not
572
     * @param boolean $nosep true to compile without seperator
573
     * @param boolean $subExp true when compile for subexpression
574
     *
575
     * @return string|null Return compiled code segment for the token when the token is custom helper
576
     */
577 491
    protected static function customHelper(&$context, $vars, $raw, $nosep, $subExp = false) {
578 491
        if (count($vars[0]) > 1) {
579 72
            return;
580
        }
581
582 439
        if (!isset($context['helpers'][$vars[0][0]])) {
583 318
            if ($subExp) {
584 7
                if ($vars[0][0] == 'lookup') {
585 3
                    return static::compileLookup($context, $vars, $raw, true);
586
                }
587
            }
588 315
            return;
589
        }
590
591 132
        $fn = $raw ? 'raw' : $context['ops']['enc'];
592 132
        $ch = array_shift($vars);
593 132
        $v = static::getVariableNames($context, $vars);
594 132
        static::addUsageCount($context, 'helpers', $ch[0]);
595 132
        $sep = $nosep ? '' : $context['ops']['seperator'];
596
597 132
        return $sep . static::getFuncName($context, 'hbch', "$ch[0] " . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, '$fn', \$in)$sep";
598
    }
599
600
    /**
601
     * Return compiled PHP code for a handlebars else token
602
     *
603
     * @param array<string,array|string|integer> $context current compile context
604
     * @param array<boolean|integer|string|array> $vars parsed arguments list
605
     *
606
     * @return string Return compiled code segment for the token when the token is else
607
     */
608 57
    protected static function doElse(&$context, $vars) {
609 57
        $v = $context['stack'][count($context['stack']) - 2];
610
611 57
        if ((($v === '[if]') && !isset($context['helpers']['if'])) ||
612 57
           (($v === '[unless]') && !isset($context['helpers']['unless']))) {
613 30
           $context['stack'][] = ':';
614 30
           return "{$context['ops']['cnd_else']}";
615
        }
616
617 30
        return "{$context['ops']['f_end']}}, function(\$cx, \$in) {{$context['ops']['array_check']}{$context['ops']['f_start']}";
618
    }
619
620
    /**
621
     * Return compiled PHP code for a handlebars log token
622
     *
623
     * @param array<string,array|string|integer> $context current compile context
624
     * @param array<boolean|integer|string|array> $vars parsed arguments list
625
     * @param boolean $raw is this {{{ token or not
626
     *
627
     * @return string Return compiled code segment for the token
628
     */
629 2
    protected static function compileLog(&$context, &$vars, $raw) {
630 2
        array_shift($vars);
631 2
        $v = static::getVariableNames($context, $vars);
632 2
        return $context['ops']['seperator'] . static::getFuncName($context, 'lo', $v[1]) . "\$cx, {$v[0]}){$context['ops']['seperator']}";
633
    }
634
635
    /**
636
     * Return compiled PHP code for a handlebars lookup token
637
     *
638
     * @param array<string,array|string|integer> $context current compile context
639
     * @param array<boolean|integer|string|array> $vars parsed arguments list
640
     * @param boolean $raw is this {{{ token or not
641
     * @param boolean $nosep true to compile without seperator
642
     *
643
     * @return string Return compiled code segment for the token
644
     */
645 8
    protected static function compileLookup(&$context, &$vars, $raw, $nosep = false) {
646 8
        $v2 = static::getVariableName($context, $vars[2]);
647 8
        $v = static::getVariableName($context, $vars[1], $v2);
648 8
        $sep = $nosep ? '' : $context['ops']['seperator'];
649 8
        $ex = $nosep ? ', 1' : '';
650
651 8
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug']) {
652 7
            return $sep . static::getFuncName($context, $raw ? 'raw' : $context['ops']['enc'], $v[1]) . "\$cx, {$v[0]}$ex){$sep}";
0 ignored issues
show
Bug introduced by
It seems like $v[1] can also be of type array<integer,string>; however, LightnCandy\Compiler::getFuncName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
653
        } else {
654 1
            return $raw ? "{$sep}$v[0]{$sep}" : "{$sep}htmlspecialchars((string){$v[0]}, ENT_QUOTES, 'UTF-8'){$sep}";
655
        }
656
    }
657
658
    /**
659
     * Return compiled PHP code for template output
660
     *
661
     * @param array<string,array|string|integer> $context current compile context
662
     * @param string $variable PHP code for the variable
663
     * @param string $expression normalized handlebars expression
664
     * @param boolean $raw is this {{{ token or not
665
     * @param boolean $nosep true to compile without seperator
666
     *
667
     * @return string Return compiled code segment for the token
668
     */
669 490
    protected static function compileOutput(&$context, $variable, $expression, $raw, $nosep) {
670 490
        $sep = $nosep ? '' : $context['ops']['seperator'];
671 490
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug'] || $nosep) {
672 440
            return $sep . static::getFuncName($context, $raw ? 'raw' : $context['ops']['enc'], $expression) . "\$cx, $variable)$sep";
673
        } else {
674 50
            return $raw ? "$sep$variable{$context['ops']['seperator']}" : "{$context['ops']['seperator']}htmlspecialchars((string)$variable, ENT_QUOTES, 'UTF-8')$sep";
675
        }
676
    }
677
678
    /**
679
     * Return compiled PHP code for a handlebars variable token
680
     *
681
     * @param array<string,array|string|integer> $context current compile context
682
     * @param array<boolean|integer|string|array> $vars parsed arguments list
683
     * @param boolean $raw is this {{{ token or not
684
     * @param boolean $nosep true to compile without seperator
685
     *
686
     * @return string Return compiled code segment for the token
687
     */
688 381
    protected static function compileVariable(&$context, &$vars, $raw, $nosep) {
689 381
        if ($context['flags']['lambda']) {
690 226
            $V = array_shift($vars);
691 226
            $v = static::getVariableName($context, $V, null, count($vars) ? static::getVariableNames($context, $vars) : array('0',array('')));
692
        } else {
693 155
            $v = static::getVariableName($context, $vars[0]);
694
        }
695 381
        return static::compileOutput($context, $v[0], $v[1], $raw, $nosep);
0 ignored issues
show
Bug introduced by
It seems like $v[1] can also be of type array<integer,string>; however, LightnCandy\Compiler::compileOutput() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
696
    }
697
698
    /**
699
     * Add usage count to context
700
     *
701
     * @param array<string,array|string|integer> $context current context
702
     * @param string $category category name, can be one of: 'var', 'helpers', 'runtime'
703
     * @param string $name used name
704
     * @param integer $count increment
705
     *
706
     * @expect 1 when input array('usedCount' => array('test' => array())), 'test', 'testname'
707
     * @expect 3 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname'
708
     * @expect 5 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname', 3
709
     */
710 646
    protected static function addUsageCount(&$context, $category, $name, $count = 1) {
711 646
        if (!isset($context['usedCount'][$category][$name])) {
712 646
            $context['usedCount'][$category][$name] = 0;
713
        }
714 646
        return ($context['usedCount'][$category][$name] += $count);
715
    }
716
}
717
718