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 ( ef104e...3d6dab )
by Zordius
03:57
created

Compiler::compileOutput()   B

Complexity

Conditions 9
Paths 6

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 9

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 7.756
cc 9
eloc 6
nc 6
nop 5
crap 9
1
<?php
2
/*
3
4
Copyrights for code authored by Yahoo! Inc. is licensed under the following terms:
5
MIT License
6
Copyright (c) 2013-2016 Yahoo! Inc. All Rights Reserved.
7
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:
8
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
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.
10
11
Origin: https://github.com/zordius/lightncandy
12
*/
13
14
/**
15
 * file of LightnCandy Compiler
16
 *
17
 * @package    LightnCandy
18
 * @author     Zordius <[email protected]>
19
 */
20
21
namespace LightnCandy;
22
23
use \LightnCandy\Validator;
24
use \LightnCandy\Token;
25
use \LightnCandy\Expression;
26
use \LightnCandy\Parser;
27
28
/**
29
 * LightnCandy Compiler
30
 */
31
class Compiler extends Validator
32
{
33
    public static $lastParsed;
34
35
    /**
36
     * Compile template into PHP code
37
     *
38
     * @param array<string,array|string|integer> $context Current context
39
     * @param string $template handlebars template
40
     *
41
     * @return string|null generated PHP code
42
     */
43 734
    public static function compileTemplate(&$context, $template) {
44 734
        array_unshift($context['parsed'], array());
45 734
        Validator::verify($context, $template);
46
47 734
        if (count($context['error'])) {
48 75
            return;
49
        }
50
51 660
        Parser::setDelimiter($context);
52
53 660
        $context['compile'] = true;
54
55
        // Handle dynamic partials
56 660
        Partial::handleDynamic($context);
57
58
        // Do PHP code generation.
59 660
        $code = '';
60 660
        foreach ($context['parsed'][0] as $info) {
61 660
            if (is_array($info)) {
62 619
                $context['tokens']['current']++;
63 619
                $code .= "'" . static::compileToken($context, $info) . "'";
64
            } else {
65 660
                $code .= $info;
66
            }
67
        }
68
69 660
        static::$lastParsed = array_shift($context['parsed']);
70
71 660
        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 659
    public static function composePHPRender($context, $code) {
83 659
        $flagJStrue = Expression::boolString($context['flags']['jstrue']);
84 659
        $flagJSObj = Expression::boolString($context['flags']['jsobj']);
85 659
        $flagSPVar = Expression::boolString($context['flags']['spvar']);
86 659
        $flagProp = Expression::boolString($context['flags']['prop']);
87 659
        $flagMethod = Expression::boolString($context['flags']['method']);
88 659
        $flagLambda = Expression::boolString($context['flags']['lambda']);
89 659
        $flagMustlok = Expression::boolString($context['flags']['mustlok']);
90 659
        $flagMustlam = Expression::boolString($context['flags']['mustlam']);
91 659
        $flagEcho = Expression::boolString($context['flags']['echo']);
92 659
        $flagPartNC = Expression::boolString($context['flags']['partnc']);
93 659
        $flagKnownHlp = Expression::boolString($context['flags']['knohlp']);
94
95 659
        $constants = Exporter::constants($context);
96 659
        $helpers = Exporter::helpers($context);
97 659
        $partials = implode(",\n", $context['partialCode']);
98 659
        $debug = Runtime::DEBUG_ERROR_LOG;
99 659
        $use = $context['flags']['standalone'] ? Exporter::runtime($context) : "use {$context['runtime']} as {$context['runtimealias']};";
100 659
        $safeString = (($context['usedFeature']['enc'] > 0) && ($context['flags']['standalone'] === 0)) ? "use {$context['safestring']} as SafeString;" : '';
101 659
        $exportSafeString = (($context['usedFeature']['enc'] > 0) && ($context['flags']['standalone'] >0)) ? Exporter::safestring($context) : '';
102
103
        // Return generated PHP code string.
104
        return <<<VAREND
105 659
$safeString{$use}{$exportSafeString}return function (\$in = null, \$options = null) {
106 659
    \$helpers = $helpers;
107 659
    \$partials = array($partials);
108
    \$cx = array(
109
        'flags' => array(
110 659
            'jstrue' => $flagJStrue,
111 659
            'jsobj' => $flagJSObj,
112 659
            'spvar' => $flagSPVar,
113 659
            'prop' => $flagProp,
114 659
            'method' => $flagMethod,
115 659
            'lambda' => $flagLambda,
116 659
            'mustlok' => $flagMustlok,
117 659
            'mustlam' => $flagMustlam,
118 659
            'echo' => $flagEcho,
119 659
            'partnc' => $flagPartNC,
120 659
            'knohlp' => $flagKnownHlp,
121 659
            'debug' => isset(\$options['debug']) ? \$options['debug'] : $debug,
122
        ),
123 659
        'constants' => $constants,
124
        'helpers' => isset(\$options['helpers']) ? array_merge(\$helpers, \$options['helpers']) : \$helpers,
125
        'partials' => isset(\$options['partials']) ? array_merge(\$partials, \$options['partials']) : \$partials,
126
        'scopes' => array(),
127
        'sp_vars' => isset(\$options['data']) ? array_merge(array('root' => \$in), \$options['data']) : array('root' => \$in),
128
        'blparam' => array(),
129
        'partialid' => 0,
130 659
        'runtime' => '{$context['runtime']}',
131
    );
132 659
    {$context['renderex']}
133 659
    {$context['ops']['op_start']}'$code'{$context['ops']['op_end']}
134 659
};
135
VAREND
136
        ;
137
    }
138
139
    /**
140
     * Get function name for standalone or none standalone template.
141
     *
142
     * @param array<string,array|string|integer> $context Current context of compiler progress.
143
     * @param string $name base function name
144
     * @param string $tag original handlabars tag for debug
145
     *
146
     * @return string compiled Function name
147
     *
148
     * @expect 'LR::test(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime', 'runtimealias' => 'LR'), 'test', ''
149
     * @expect 'LL::test2(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime', 'runtimealias' => 'LL'), 'test2', ''
150
     * @expect "lala_abctest3(" when input array('flags' => array('standalone' => 1, 'debug' => 0), 'runtime' => 'Runtime', 'runtimealias' => 0, 'funcprefix' => 'lala_abc'), 'test3', ''
151
     * @expect 'RR::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1), 'runtime' => 'Runtime', 'runtimealias' => 'RR', 'funcprefix' => 'haha456'), 'test', 'abc'
152
     */
153 594
    protected static function getFuncName(&$context, $name, $tag) {
154 594
        static::addUsageCount($context, 'runtime', $name);
155
156 594
        if ($context['flags']['debug'] && ($name != 'miss')) {
157 10
            $dbg = "'$tag', '$name', ";
158 10
            $name = 'debug';
159 10
            static::addUsageCount($context, 'runtime', 'debug');
160
        } else {
161 592
            $dbg = '';
162
        }
163
164 594
        return $context['flags']['standalone'] ? "{$context['funcprefix']}$name($dbg" : "{$context['runtimealias']}::$name($dbg";
165
    }
166
167
    /**
168
     * Get string presentation of variables
169
     *
170
     * @param array<string,array|string|integer> $context current compile context
171
     * @param array<array> $vn variable name array.
172
     * @param array<string>|null $blockParams block param list
173
     *
174
     * @return array<string|array> variable names
175
     *
176
     * @expect array('array(array($in),array())', array('this')) when input array('flags'=>array('spvar'=>true)), array(null)
177
     * @expect array('array(array($in,$in),array())', array('this', 'this')) when input array('flags'=>array('spvar'=>true)), array(null, null)
178
     * @expect array('array(array(),array(\'a\'=>$in))', array('this')) when input array('flags'=>array('spvar'=>true)), array('a' => null)
179
     */
180 262
    protected static function getVariableNames(&$context, $vn, $blockParams = null) {
181 262
        $vars = array(array(), array());
182 262
        $exps = array();
183 262
        foreach ($vn as $i => $v) {
184 224
            $V = static::getVariableNameOrSubExpression($context, $v);
185 224
            if (is_string($i)) {
186 37
                $vars[1][] = "'$i'=>{$V[0]}";
187
            } else {
188 210
                $vars[0][] = $V[0];
189
            }
190 224
            $exps[] = $V[1];
191
        }
192 262
        $bp = $blockParams ? (',array(' . Expression::listString($blockParams) . ')') : '';
193 262
        return array('array(array(' . implode(',', $vars[0]) . '),array(' . implode(',', $vars[1]) . ")$bp)", $exps);
194
    }
195
196
    /**
197
     * Get string presentation of a sub expression
198
     *
199
     * @param array<string,array|string|integer> $context current compile context
200
     * @param array<boolean|integer|string|array> $vars parsed arguments list
201
     *
202
     * @return array<string> code representing passed expression
203
     */
204 41
    public static function compileSubExpression(&$context, $vars) {
205 41
        $ret = static::customHelper($context, $vars, true, true);
206
207 41
        if (($ret === null) && $context['flags']['lambda']) {
208 4
            $ret = static::compileVariable($context, $vars, true, true);
209
        }
210
211 41
        return array($ret ? $ret : '', 'FIXME: $subExpression');
212
    }
213
214
    /**
215
     * Get string presentation of a subexpression or a variable
216
     *
217
     * @param array<array|string|integer> $context current compile context
218
     * @param array<array|string|integer> $var variable parsed path
219
     *
220
     * @return array<string> variable names
0 ignored issues
show
Documentation introduced by
Should the return type not be array<array|string|integer>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
221
     */
222 373
    protected static function getVariableNameOrSubExpression(&$context, $var) {
223 373
        return Parser::isSubExp($var) ? static::compileSubExpression($context, $var[1]) : static::getVariableName($context, $var);
224
    }
225
226
    /**
227
     * Get string presentation of a variable
228
     *
229
     * @param array<array|string|integer> $var variable parsed path
230
     * @param array<array|string|integer> $context current compile context
231
     * @param array<string>|null $lookup extra lookup string as valid PHP variable name
232
     *
233
     * @return array<string> variable names
0 ignored issues
show
Documentation introduced by
Should the return type not be array<array|string|integer>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
234
     *
235
     * @expect array('$in', 'this') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(null)
236
     * @expect array('((is_array($in) && 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')
237
     * @expect array('((is_array($in) && 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')
238
     * @expect array('true', 'true') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'true')
239
     * @expect array('false', 'false') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'false')
240
     * @expect array('((is_array($in) && 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')
241
     * @expect array('2', '2') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0)), array(-1, '2')
242
     * @expect array('((is_array($in) && 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')
243
     * @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')
244
     * @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')
245
     * @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')
246
     * @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')
247
     * @expect array('((is_array($in) && 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"')
248
     * @expect array('"a"', '"a"') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, '"a"')
249
     * @expect array('((is_array($in) && 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')
250
     * @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')
251
     * @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')
252
     * @expect array('((is_array($in) && 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')
253
     * @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')
254
     */
255 590
    protected static function getVariableName(&$context, $var, $lookup = null, $args = null) {
256 590
        if (isset($var[0]) && ($var[0] === Parser::LITERAL)) {
257 82
            if ($var[1] === "undefined") {
258 2
                $var[1] = "null";
259
            }
260 82
            return array($var[1], preg_replace('/\'(.*)\'/', '$1', $var[1]));
261
        }
262
263 549
        list($levels, $spvar, $var) = Expression::analyze($context, $var);
0 ignored issues
show
Documentation introduced by
$var is of type array<integer,array|stri...array|string|integer"}>, but the function expects a array<integer,array|string|integer>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
264 549
        $exp = Expression::toString($levels, $spvar, $var);
265 549
        $base = $spvar ? "\$cx['sp_vars']" : '$in';
266 549
        $is_array_check = $spvar ? false : true;
267
268
        // change base when trace to parent
269 549
        if ($levels > 0) {
270 40
            if ($spvar) {
271 2
                $base .= str_repeat("['_parent']", $levels);
272
            } else {
273 38
                $base = "\$cx['scopes'][count(\$cx['scopes'])-$levels]";
274
            }
275
        }
276
277 549
        if ((count($var) == 0) || (($var[0] === null) && (count($var) == 1))) {
278 135
            return array($base, $exp);
279
        }
280
281 492
        if ($var[0] === null) {
282 1
            array_shift($var);
283
        }
284
285
        // To support recursive context lookup, instance properties + methods and lambdas
286
        // the only way is using slower rendering time variable resolver.
287 492
        if ($context['flags']['prop'] || $context['flags']['method'] || $context['flags']['mustlok'] || $context['flags']['mustlam'] || $context['flags']['lambda']) {
288 386
            $L = $lookup ? ", $lookup[0]" : '';
289 386
            $A = $args ? ",$args[0]" : '';
290 386
            $E = $args ? ' ' . implode(' ', $args[1]) : '';
291 386
            return array(static::getFuncName($context, 'v', $exp) . "\$cx, \$in, isset($base) ? $base : null, array(" . Expression::listString($var) . "$L)$A)", $lookup ? "lookup $exp $lookup[1]" : "$exp$E");
292
        }
293
294 107
        $n = Expression::arrayString($var);
295 107
        $k = array_pop($var);
296 107
        $L = $lookup ? "[{$lookup[0]}]" : '';
297 107
        $p = $lookup ? $n : (count($var) ? Expression::arrayString($var) : '');
298
299 107
        $checks = array();
300 107
        if ($levels > 0) {
301 10
            $checks[] = "isset($base)";
302
        }
303 107
        if ($is_array_check) {
304 104
            $checks[] = "is_array($base$p)";
305
        }
306 107
        $checks[] = "isset($base$n$L)";
307 107
        $check = ((count($checks) > 1) ? '(' : '') . implode(' && ', $checks) . ((count($checks) > 1) ? ')' : '');
308
309 107
        $lenStart = '';
310 107
        $lenEnd = '';
311
312 107
        if ($context['flags']['jslen']) {
313 50
            if (($lookup === null) && ($k === 'length')) {
314 1
                array_pop($checks);
315 1
                $lenStart = '(' . ((count($checks) > 1) ? '(' : '') . implode(' && ', $checks) . ((count($checks) > 1) ? ')' : '') . " ? count($base" . Expression::arrayString($var) . ') : ';
316 1
                $lenEnd = ')';
317
            }
318
        }
319
320 107
        return array("($check ? $base$n$L : $lenStart" . ($context['flags']['debug'] ? (static::getFuncName($context, 'miss', '') . "\$cx, '$exp')") : 'null' ) . ")$lenEnd", $lookup ? "lookup $exp $lookup[1]" : $exp);
321
    }
322
323
    /**
324
     * Return compiled PHP code for a handlebars token
325
     *
326
     * @param array<string,array|string|integer> $context current compile context
327
     * @param array<string,array|boolean> $info parsed information
328
     *
329
     * @return string Return compiled code segment for the token
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|integer|double|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
330
     */
331 619
    protected static function compileToken(&$context, $info) {
332 619
        list($raw, $vars, $token, $indent) = $info;
333
334 619
        $context['tokens']['partialind'] = $indent;
335 619
        $context['currentToken'] = $token;
336
337 619
        if ($ret = static::operator($token[Token::POS_OP], $context, $vars)) {
338 380
            return $ret;
339
        }
340
341 480
        if (isset($vars[0][0])) {
342 448
            if ($ret = static::customHelper($context, $vars, $raw, true)) {
343 113
                return static::compileOutput($context, $ret, 'FIXME: helper', $raw, false);
344
            }
345 342
            if ($vars[0][0] === 'else') {
346 28
                return static::doElse($context, $vars);
347
            }
348 325
            if ($vars[0][0] === 'lookup') {
349 2
                return static::compileLookup($context, $vars, $raw);
350
            }
351 323
            if ($vars[0][0] === 'log') {
352 2
                return static::compileLog($context, $vars, $raw);
353
            }
354
        }
355
356 358
        return static::compileVariable($context, $vars, $raw, false);
357
    }
358
359
    /**
360
     * handle partial
361
     *
362
     * @param array<string,array|string|integer> $context current compile context
363
     * @param array<boolean|integer|string|array> $vars parsed arguments list
364
     *
365
     * @return string Return compiled code segment for the partial
366
     */
367 88
    public static function partial(&$context, $vars) {
368 88
        Parser::getBlockParams($vars);
0 ignored issues
show
Documentation introduced by
$vars is of type array<integer,boolean|integer|string|array>, but the function expects a array<integer,boolean|integer|array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
369 88
        $pid = Parser::getPartialBlock($vars);
370 88
        $p = array_shift($vars);
371 88
        if ($context['flags']['runpart']) {
372 79
            if (!isset($vars[0])) {
373 72
                $vars[0] = $context['flags']['partnc'] ? array(0, 'null') : array();
374
            }
375 79
            $v = static::getVariableNames($context, $vars);
376 79
            $tag = ">$p[0] " .implode(' ', $v[1]);
377 79
            if (Parser::isSubExp($p)) {
378 4
                list($p) = static::compileSubExpression($context, $p[1]);
379
            } else {
380 75
                $p = "'$p[0]'";
381
            }
382 79
            $sp = $context['tokens']['partialind'] ? ", '{$context['tokens']['partialind']}'" : '';
383 79
            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...
384
        }
385 9
        return isset($context['usedPartial'][$p[0]]) ? "{$context['ops']['seperator']}'" . Partial::compileStatic($context, $p[0]) . "'{$context['ops']['seperator']}" : $context['ops']['seperator'];
386
    }
387
388
    /**
389
     * handle inline partial
390
     *
391
     * @param array<string,array|string|integer> $context current compile context
392
     * @param array<boolean|integer|string|array> $vars parsed arguments list
393
     *
394
     * @return string Return compiled code segment for the partial
395
     */
396 10
    public static function inline(&$context, $vars) {
397 10
        Parser::getBlockParams($vars);
0 ignored issues
show
Documentation introduced by
$vars is of type array<integer,boolean|integer|string|array>, but the function expects a array<integer,boolean|integer|array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
398 10
        list($code) = array_shift($vars);
399 10
        $p = array_shift($vars);
400 10
        if (!isset($vars[0])) {
401 10
            $vars[0] = $context['flags']['partnc'] ? array(0, 'null') : array();
402
        }
403 10
        $v = static::getVariableNames($context, $vars);
404 10
        $tag = ">*inline $p[0]" .implode(' ', $v[1]);
405 10
        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...
406
    }
407
408
    /**
409
     * Return compiled PHP code for a handlebars inverted section begin token
410
     *
411
     * @param array<string,array|string|integer> $context current compile context
412
     * @param array<boolean|integer|string|array> $vars parsed arguments list
413
     *
414
     * @return string Return compiled code segment for the token
415
     */
416 38
    protected static function invertedSection(&$context, $vars) {
417 38
        $v = static::getVariableName($context, $vars[0]);
418 38
        return "{$context['ops']['cnd_start']}(" . static::getFuncName($context, 'isec', '^' . $v[1]) . "\$cx, {$v[0]})){$context['ops']['cnd_then']}";
419
    }
420
421
    /**
422
     * Return compiled PHP code for a handlebars block custom helper begin token
423
     *
424
     * @param array<string,array|string|integer> $context current compile context
425
     * @param array<boolean|integer|string|array> $vars parsed arguments list
426
     * @param boolean $inverted the logic will be inverted
427
     *
428
     * @return string Return compiled code segment for the token
429
     */
430 60
    protected static function blockCustomHelper(&$context, $vars, $inverted = false) {
431 60
        $bp = Parser::getBlockParams($vars);
0 ignored issues
show
Documentation introduced by
$vars is of type array<integer,boolean|integer|string|array>, but the function expects a array<integer,boolean|integer|array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
432 60
        $ch = array_shift($vars);
433 60
        $inverted = $inverted ? 'true' : 'false';
434 60
        static::addUsageCount($context, 'helpers', $ch[0]);
435 60
        $v = static::getVariableNames($context, $vars, $bp);
436
437 60
        return $context['ops']['seperator'] . static::getFuncName($context, 'hbch', ($inverted ? '^' : '#') . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, \$in, $inverted, function(\$cx, \$in) {{$context['ops']['f_start']}";
438
    }
439
440
    /**
441
     * Return compiled PHP code for a handlebars block end token
442
     *
443
     * @param array<string,array|string|integer> $context current compile context
444
     * @param array<boolean|integer|string|array> $vars parsed arguments list
445
     * @param string|null $matchop should also match to this operator
446
     *
447
     * @return string Return compiled code segment for the token
448
     */
449 321
    protected static function blockEnd(&$context, &$vars, $matchop = NULL) {
450 321
        $pop = $context['stack'][count($context['stack']) - 1];
451 321
        $elsifend = isset($vars[0][-1]) ? str_repeat($context['ops']['cnd_nend'], $vars[0][-1]) : '';
452 321
        switch ($context['currentToken'][Token::POS_INNERTAG]) {
453 321
            case 'if':
454 268
            case 'unless':
455 71
                if ($pop === ':') {
456 19
                    array_pop($context['stack']);
457 19
                    return "$elsifend{$context['ops']['cnd_end']}";
458
                }
459 52
                if (!$context['flags']['nohbh']) {
460 50
                    return "{$context['ops']['cnd_else']}''$elsifend{$context['ops']['cnd_end']}";
461
                }
462 2
                break;
463 264
            case 'with':
464 33
                if (!$context['flags']['nohbh']) {
465 32
                    return "$elsifend{$context['ops']['f_end']}}){$context['ops']['seperator']}";
466
                }
467
        }
468
469 242
        if ($pop === ':') {
470 2
            array_pop($context['stack']);
471 2
            return "$elsifend{$context['ops']['f_end']}}){$context['ops']['seperator']}";
472
        }
473
474 240
        if ($elsifend !== '') {
475 3
            $elsifend = "{$context['ops']['cnd_else']}''$elsifend";
476
        }
477
478
        switch($pop) {
479 240
            case '#':
480 215
                return "$elsifend{$context['ops']['f_end']}}){$context['ops']['seperator']}";
481 33
            case '^':
482 33
                return "$elsifend{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
483
        }
484
    }
485
486
    /**
487
     * Return compiled PHP code for a handlebars block begin token
488
     *
489
     * @param array<string,array|string|integer> $context current compile context
490
     * @param array<boolean|integer|string|array> $vars parsed arguments list
491
     *
492
     * @return string Return compiled code segment for the token
493
     */
494 239
    protected static function blockBegin(&$context, $vars) {
495 239
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($context, $vars[1]) : array(null, array());
496 239
        if (!$context['flags']['nohbh']) {
497 201
            switch (isset($vars[0][0]) ? $vars[0][0] : null) {
498 201
                case 'if':
499 66
                    $includeZero = (isset($vars['includeZero'][1]) && $vars['includeZero'][1]) ? 'true' : 'false';
500 66
                    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...
501 152
                case 'unless':
502 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...
503 149
                case 'each':
504 47
                    return static::section($context, $vars, true);
0 ignored issues
show
Documentation introduced by
$vars is of type array<integer,boolean|in...er|string|array|null"}>, but the function expects a array<integer,boolean|integer|string|array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug Best Practice introduced by
The return type of return static::section($context, $vars, true); (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...
505 104
                case 'with':
506 28
                    if ($r = static::with($context, $vars)) {
0 ignored issues
show
Documentation introduced by
$vars is of type array<integer,boolean|in...er|string|array|null"}>, but the function expects a array<integer,boolean|integer|string|array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
507 28
                        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...
508
                    }
509
            }
510
        }
511
512 116
        return static::section($context, $vars);
0 ignored issues
show
Documentation introduced by
$vars is of type array<integer,boolean|in...er|string|array|null"}>, but the function expects a array<integer,boolean|integer|string|array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug Best Practice introduced by
The return type of return static::section($context, $vars); (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...
513
    }
514
515
    /**
516
     * compile {{#foo}} token
517
     *
518
     * @param array<string,array|string|integer> $context current compile context
519
     * @param array<boolean|integer|string|array> $vars parsed arguments list
520
     * @param boolean $isEach the section is #each
521
     *
522
     * @return string|null Return compiled code segment for the token
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
523
     */
524 163
    protected static function section(&$context, $vars, $isEach = false) {
525 163
        $bs = 'null';
526 163
        $be = '';
527 163
        if ($isEach) {
528 47
            $bp = Parser::getBlockParams($vars);
0 ignored issues
show
Documentation introduced by
$vars is of type array<integer,boolean|integer|string|array>, but the function expects a array<integer,boolean|integer|array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
529 47
            $bs = $bp ? ('array(' . Expression::listString($bp) . ')') : 'null';
530 47
            $be = $bp ? " as |$bp[0] $bp[1]|" : '';
531 47
            array_shift($vars);
532
        }
533 163
        if ($context['flags']['lambda'] && !$isEach) {
534 69
            $V = array_shift($vars);
535 69
            $v = static::getVariableName($context, $V, null, count($vars) ? static::getVariableNames($context, $vars) : array('0',array('')));
536
        } else {
537 94
            $v = static::getVariableNameOrSubExpression($context, $vars[0]);
538
        }
539 163
        $each = $isEach ? 'true' : 'false';
540 163
        return $context['ops']['seperator'] . static::getFuncName($context, 'sec', ($isEach ? 'each ' : '') . $v[1] . $be) . "\$cx, {$v[0]}, $bs, \$in, $each, function(\$cx, \$in) {{$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...
541
    }
542
543
    /**
544
     * compile {{with}} token
545
     *
546
     * @param array<string,array|string|integer> $context current compile context
547
     * @param array<boolean|integer|string|array> $vars parsed arguments list
548
     *
549
     * @return string|null Return compiled code segment for the token
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
550
     */
551 28
    protected static function with(&$context, $vars) {
552 28
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($context, $vars[1]) : array(null, array());
553 28
        $bp = Parser::getBlockParams($vars);
0 ignored issues
show
Documentation introduced by
$vars is of type array<integer,boolean|in...er|string|array|null"}>, but the function expects a array<integer,boolean|integer|array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
554 28
        $bs = $bp ? ('array(' . Expression::listString($bp) . ')') : 'null';
555 28
        $be = $bp ? " as |$bp[0]|" : '';
556 28
        return $context['ops']['seperator'] . static::getFuncName($context, 'wi', 'with ' . $v[1] . $be) . "\$cx, {$v[0]}, $bs, \$in, function(\$cx, \$in) {{$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...
557
    }
558
559
    /**
560
     * Return compiled PHP code for a handlebars custom helper token
561
     *
562
     * @param array<string,array|string|integer> $context current compile context
563
     * @param array<boolean|integer|string|array> $vars parsed arguments list
564
     * @param boolean $raw is this {{{ token or not
565
     * @param boolean $nosep true to compile without seperator
566
     *
567
     * @return string|null Return compiled code segment for the token when the token is custom helper
568
     */
569 456
    protected static function customHelper(&$context, $vars, $raw, $nosep) {
570 456
        if (!isset($context['helpers'][$vars[0][0]])) {
571 345
            return;
572
        }
573
574 124
        $fn = $raw ? 'raw' : $context['ops']['enc'];
575 124
        $ch = array_shift($vars);
576 124
        $v = static::getVariableNames($context, $vars);
577 124
        static::addUsageCount($context, 'helpers', $ch[0]);
578 124
        $sep = $nosep ? '' : $context['ops']['seperator'];
579
580 124
        return $sep . static::getFuncName($context, 'hbch', "$ch[0] " . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, '$fn', \$in)$sep";
581
    }
582
583
    /**
584
     * Return compiled PHP code for a handlebars else token
585
     *
586
     * @param array<string,array|string|integer> $context current compile context
587
     * @param array<boolean|integer|string|array> $vars parsed arguments list
588
     *
589
     * @return string Return compiled code segment for the token when the token is else
590
     */
591 50
    protected static function doElse(&$context, $vars) {
592 50
        switch ($context['stack'][count($context['stack']) - 2]) {
593 50
            case '[if]':
594 29
            case '[unless]':
595 24
                $context['stack'][] = ':';
596 24
                return "{$context['ops']['cnd_else']}";
597
            default:
598 29
                return "{$context['ops']['f_end']}}, function(\$cx, \$in) {{$context['ops']['f_start']}";
599
        }
600
    }
601
602
    /**
603
     * Return compiled PHP code for a handlebars log token
604
     *
605
     * @param array<string,array|string|integer> $context current compile context
606
     * @param array<boolean|integer|string|array> $vars parsed arguments list
607
     * @param boolean $raw is this {{{ token or not
608
     *
609
     * @return string Return compiled code segment for the token
610
     */
611 2
    protected static function compileLog(&$context, &$vars, $raw) {
0 ignored issues
show
Unused Code introduced by
The parameter $raw is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
612 2
        array_shift($vars);
613 2
        $v = static::getVariableNames($context, $vars);
614 2
        return $context['ops']['seperator'] . static::getFuncName($context, 'lo', $v[1]) . "\$cx, {$v[0]}){$context['ops']['seperator']}";
0 ignored issues
show
Documentation introduced by
$v[1] is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
615
    }
616
617
    /**
618
     * Return compiled PHP code for a handlebars lookup token
619
     *
620
     * @param array<string,array|string|integer> $context current compile context
621
     * @param array<boolean|integer|string|array> $vars parsed arguments list
622
     * @param boolean $raw is this {{{ token or not
623
     *
624
     * @return string Return compiled code segment for the token
625
     */
626 2
    protected static function compileLookup(&$context, &$vars, $raw) {
627 2
        $v2 = static::getVariableName($context, $vars[2]);
628 2
        $v = static::getVariableName($context, $vars[1], $v2);
0 ignored issues
show
Documentation introduced by
$v2 is of type array<integer,array|stri...rray<integer,string>"}>, but the function expects a array<integer,string>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
629 2
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug']) {
630 2
            return $context['ops']['seperator'] . static::getFuncName($context, $raw ? 'raw' : $context['ops']['enc'], $v[1]) . "\$cx, {$v[0]}){$context['ops']['seperator']}";
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...
631
        } else {
632
            return $raw ? "{$context['ops']['seperator']}$v[0]{$context['ops']['seperator']}" : "{$context['ops']['seperator']}htmlentities((string){$v[0]}, ENT_QUOTES, 'UTF-8'){$context['ops']['seperator']}";
633
        }
634
    }
635
636
    /**
637
     * Return compiled PHP code for template output
638
     *
639
     * @param array<string,array|string|integer> $context current compile context
640
     * @param string $variable PHP code for the variable
641
     * @param string $expression normalized handlebars expression
642
     * @param boolean $raw is this {{{ token or not
643
     * @param boolean $nosep true to compile without seperator
644
     *
645
     * @return string Return compiled code segment for the token
646
     */
647 462
    protected static function compileOutput(&$context, $variable, $expression, $raw, $nosep) {
648 462
        $sep = $nosep ? '' : $context['ops']['seperator'];
649 462
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug'] || $nosep) {
650 420
            return $sep . static::getFuncName($context, $raw ? 'raw' : $context['ops']['enc'], $expression) . "\$cx, $variable)$sep";
651
        } else {
652 42
            return $raw ? "$sep$variable{$context['ops']['seperator']}" : "{$context['ops']['seperator']}htmlentities((string)$variable, ENT_QUOTES, 'UTF-8')$sep";
653
        }
654
    }
655
656
    /**
657
     * Return compiled PHP code for a handlebars variable token
658
     *
659
     * @param array<string,array|string|integer> $context current compile context
660
     * @param array<boolean|integer|string|array> $vars parsed arguments list
661
     * @param boolean $raw is this {{{ token or not
662
     * @param boolean $nosep true to compile without seperator
663
     *
664
     * @return string Return compiled code segment for the token
665
     */
666 361
    protected static function compileVariable(&$context, &$vars, $raw, $nosep) {
667 361
        if ($context['flags']['lambda']) {
668 227
            $V = array_shift($vars);
669 227
            $v = static::getVariableName($context, $V, null, count($vars) ? static::getVariableNames($context, $vars) : array('0',array('')));
670
        } else {
671 134
            $v = static::getVariableName($context, $vars[0]);
672
        }
673 361
        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...
674
    }
675
676
    /**
677
     * Add usage count to context
678
     *
679
     * @param array<string,array|string|integer> $context current context
680
     * @param string $category category name, can be one of: 'var', 'helpers', 'runtime'
681
     * @param string $name used name
682
     * @param integer $count increment
683
     *
684
     * @expect 1 when input array('usedCount' => array('test' => array())), 'test', 'testname'
685
     * @expect 3 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname'
686
     * @expect 5 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname', 3
687
     */
688 594
    protected static function addUsageCount(&$context, $category, $name, $count = 1) {
689 594
        if (!isset($context['usedCount'][$category][$name])) {
690 594
            $context['usedCount'][$category][$name] = 0;
691
        }
692 594
        return ($context['usedCount'][$category][$name] += $count);
693
    }
694
}
695
696