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 — v0.89-develop ( f4df6d...71130e )
by Zordius
02:25
created

Compiler::with()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 4
Bugs 0 Features 1
Metric Value
c 4
b 0
f 1
dl 0
loc 7
ccs 6
cts 6
cp 1
rs 9.2
cc 4
eloc 6
nc 8
nop 2
crap 4
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-2015 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 715
    public static function compileTemplate(&$context, $template) {
44 715
        array_unshift($context['parsed'], array());
45 715
        Validator::verify($context, $template);
46
47 715
        if (count($context['error'])) {
48 70
            return;
49
        }
50
51
        // Do PHP code generation.
52 646
        Parser::setDelimiter($context);
53
54
        // Handle dynamic partials
55 646
        Partial::handleDynamic($context);
56
57 646
        $code = '';
58 646
        foreach ($context['parsed'][0] as $info) {
59 646
            if (is_array($info)) {
60 605
                $context['tokens']['current']++;
61 605
                $tmpl = static::compileToken($context, $info);
62 605
                if ($tmpl == $context['ops']['seperator']) {
63 1
                    $tmpl = '';
64
                } else {
65 604
                    $tmpl = "'$tmpl'";
66
                }
67 605
                $code .= $tmpl;
68
            } else {
69 646
                $code .= $info;
70
            }
71
        }
72
73 646
        static::$lastParsed = array_shift($context['parsed']);
74
75 646
        return $code;
76
    }
77
78
    /**
79
     * Compose LightnCandy render codes for include()
80
     *
81
     * @param array<string,array|string|integer> $context Current context
82
     * @param string $code generated PHP code
83
     *
84
     * @return string Composed PHP code
85
     */
86 645
    public static function composePHPRender($context, $code) {
87 645
        $flagJStrue = Expression::boolString($context['flags']['jstrue']);
88 645
        $flagJSObj = Expression::boolString($context['flags']['jsobj']);
89 645
        $flagSPVar = Expression::boolString($context['flags']['spvar']);
90 645
        $flagProp = Expression::boolString($context['flags']['prop']);
91 645
        $flagMethod = Expression::boolString($context['flags']['method']);
92 645
        $flagLambda = Expression::boolString($context['flags']['lambda']);
93 645
        $flagMustlok = Expression::boolString($context['flags']['mustlok']);
94 645
        $flagMustlam = Expression::boolString($context['flags']['mustlam']);
95 645
        $flagEcho = Expression::boolString($context['flags']['echo']);
96 645
        $flagPartNC = Expression::boolString($context['flags']['partnc']);
97 645
        $flagKnownHlp = Expression::boolString($context['flags']['knohlp']);
98
99 645
        $libstr = Exporter::runtime($context);
100 645
        $constants = Exporter::constants($context);
101 645
        $helpers = Exporter::helpers($context);
102 645
        $bhelpers = Exporter::helpers($context, 'blockhelpers');
103 645
        $hbhelpers = Exporter::helpers($context, 'hbhelpers');
104 645
        $partials = implode(",\n", $context['partialCode']);
105 645
        $debug = Runtime::DEBUG_ERROR_LOG;
106 645
        $phpstart = $context['flags']['bare'] ? '' : "<?php use {$context['runtime']} as LR;\n";
107 645
        $phpend = $context['flags']['bare'] ? ';' : "\n?>";
108
109
        // Return generated PHP code string.
110 645
        return "{$phpstart}return function (\$in, \$options = null) {
111
    \$cx = array(
112
        'flags' => array(
113
            'jstrue' => $flagJStrue,
114
            'jsobj' => $flagJSObj,
115
            'spvar' => $flagSPVar,
116
            'prop' => $flagProp,
117
            'method' => $flagMethod,
118
            'lambda' => $flagLambda,
119
            'mustlok' => $flagMustlok,
120
            'mustlam' => $flagMustlam,
121
            'echo' => $flagEcho,
122
            'partnc' => $flagPartNC,
123
            'knohlp' => $flagKnownHlp,
124
            'debug' => isset(\$options['debug']) ? \$options['debug'] : $debug,
125
        ),
126
        'constants' => $constants,
127
        'helpers' => $helpers,
128
        'blockhelpers' => $bhelpers,
129
        'hbhelpers' => isset(\$options['helpers']) ? array_merge($hbhelpers, \$options['helpers']) : $hbhelpers,
130
        'partials' => array($partials),
131
        'scopes' => array(),
132
        'sp_vars' => isset(\$options['data']) ? array_merge(array('root' => \$in), \$options['data']) : array('root' => \$in),
133
        'blparam' => array(),
134 645
        'runtime' => '{$context['runtime']}',
135
$libstr
136
    );
137 645
    {$context['renderex']}
138 645
    {$context['ops']['op_start']}'$code'{$context['ops']['op_end']}
139 645
}$phpend";
140
    }
141
142
    /**
143
     * Get function name for standalone or none standalone template.
144
     *
145
     * @param array<string,array|string|integer> $context Current context of compiler progress.
146
     * @param string $name base function name
147
     * @param string $tag original handlabars tag for debug
148
     *
149
     * @return string compiled Function name
150
     *
151
     * @expect 'LR::test(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime'), 'test', ''
152
     * @expect 'LR::test2(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime'), 'test2', ''
153
     * @expect "\$cx['funcs']['test3'](" when input array('flags' => array('standalone' => 1, 'debug' => 0), 'runtime' => 'Runtime'), 'test3', ''
154
     * @expect 'LR::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1), 'runtime' => 'Runtime'), 'test', 'abc'
155
     */
156 581
    protected static function getFuncName(&$context, $name, $tag) {
157 581
        static::addUsageCount($context, 'runtime', $name);
158
159 581
        if ($context['flags']['debug'] && ($name != 'miss')) {
160 10
            $dbg = "'$tag', '$name', ";
161 10
            $name = 'debug';
162 10
            static::addUsageCount($context, 'runtime', 'debug');
163
        } else {
164 579
            $dbg = '';
165
        }
166
167 581
        return $context['flags']['standalone'] ? "\$cx['funcs']['$name']($dbg" : "LR::$name($dbg";
168
    }
169
170
    /**
171
     * Get string presentation of variables
172
     *
173
     * @param array<string,array|string|integer> $context current compile context
174
     * @param array<array> $vn variable name array.
175
     * @param array<string>|null $blockParams block param list
176
     *
177
     * @return array<string|array> variable names
178
     *
179
     * @expect array('array(array($in),array())', array('this')) when input array('flags'=>array('spvar'=>true)), array(null)
180
     * @expect array('array(array($in,$in),array())', array('this', 'this')) when input array('flags'=>array('spvar'=>true)), array(null, null)
181
     * @expect array('array(array(),array(\'a\'=>$in))', array('this')) when input array('flags'=>array('spvar'=>true)), array('a' => null)
182
     */
183 258
    protected static function getVariableNames(&$context, $vn, $blockParams = null) {
184 258
        $vars = array(array(), array());
185 258
        $exps = array();
186 258
        foreach ($vn as $i => $v) {
187 219
            $V = static::getVariableNameOrSubExpression($context, $v);
188 219
            if (is_string($i)) {
189 36
                $vars[1][] = "'$i'=>{$V[0]}";
190
            } else {
191 205
                $vars[0][] = $V[0];
192
            }
193 219
            $exps[] = $V[1];
194
        }
195 258
        $bp = $blockParams ? (',array(' . Expression::listString($blockParams) . ')') : '';
196 258
        return array('array(array(' . implode(',', $vars[0]) . '),array(' . implode(',', $vars[1]) . ")$bp)", $exps);
197
    }
198
199
    /**
200
     * Get string presentation of a sub expression
201
     *
202
     * @param array<string,array|string|integer> $context current compile context
203
     * @param array<boolean|integer|string|array> $vars parsed arguments list
204
     *
205
     * @return array<string> code representing passed expression
206
     */
207 41
    public static function compileSubExpression(&$context, $vars) {
208 41
        $origSeperator = $context['ops']['seperator'];
209 41
        $context['ops']['seperator'] = '';
210
211 41
        $ret = static::customHelper($context, $vars, true);
212
213 41
        if (($ret === null) && $context['flags']['lambda']) {
214 4
            $ret = static::compileVariable($context, $vars, true);
215
        }
216
217 41
        $context['ops']['seperator'] = $origSeperator;
218
219 41
        return array($ret ? $ret : '', 'FIXME: $subExpression');
220
    }
221
222
    /**
223
     * Get string presentation of a subexpression or a variable
224
     *
225
     * @param array<array|string|integer> $context current compile context
226
     * @param array<array|string|integer> $var variable parsed path
227
     *
228
     * @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...
229
     */
230 360
    protected static function getVariableNameOrSubExpression(&$context, $var) {
231 360
        return Parser::isSubExp($var) ? static::compileSubExpression($context, $var[1]) : static::getVariableName($context, $var);
232
    }
233
234
    /**
235
     * Get string presentation of a variable
236
     *
237
     * @param array<array|string|integer> $var variable parsed path
238
     * @param array<array|string|integer> $context current compile context
239
     * @param array<string> $lookup extra lookup string as valid PHP variable name
0 ignored issues
show
Documentation introduced by
Should the type for parameter $lookup not be string[]|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
240
     *
241
     * @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...
242
     *
243
     * @expect array('$in', 'this') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(null)
244
     * @expect array('((isset($in[\'true\']) && is_array($in)) ? $in[\'true\'] : null)', '[true]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('true')
245
     * @expect array('((isset($in[\'false\']) && is_array($in)) ? $in[\'false\'] : null)', '[false]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('false')
246
     * @expect array('true', 'true') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'true')
247
     * @expect array('false', 'false') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'false')
248
     * @expect array('((isset($in[\'2\']) && is_array($in)) ? $in[\'2\'] : null)', '[2]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('2')
249
     * @expect array('2', '2') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0)), array(-1, '2')
250
     * @expect array('((isset($in[\'@index\']) && is_array($in)) ? $in[\'@index\'] : null)', '[@index]') when input array('flags'=>array('spvar'=>false,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('@index')
251
     * @expect array("((isset(\$cx['sp_vars']['index']) && is_array(\$cx['sp_vars'])) ? \$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)), array('@index')
252
     * @expect array("((isset(\$cx['sp_vars']['key']) && is_array(\$cx['sp_vars'])) ? \$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)), array('@key')
253
     * @expect array("((isset(\$cx['sp_vars']['first']) && is_array(\$cx['sp_vars'])) ? \$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)), array('@first')
254
     * @expect array("((isset(\$cx['sp_vars']['last']) && is_array(\$cx['sp_vars'])) ? \$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)), array('@last')
255
     * @expect array('((isset($in[\'"a"\']) && is_array($in)) ? $in[\'"a"\'] : null)', '["a"]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('"a"')
256
     * @expect array('"a"', '"a"') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, '"a"')
257
     * @expect array('((isset($in[\'a\']) && is_array($in)) ? $in[\'a\'] : null)', '[a]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array('a')
258
     * @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-1][\'a\']) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-1])) ? $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)), array(1,'a')
259
     * @expect array('((isset($cx[\'scopes\'][count($cx[\'scopes\'])-3][\'a\']) && is_array($cx[\'scopes\'][count($cx[\'scopes\'])-3])) ? $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)), array(3,'a')
260
     * @expect array('((isset($in[\'id\']) && is_array($in)) ? $in[\'id\'] : null)', 'this.[id]') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0)), array(null, 'id')
261
     * @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,'standalone'=>0), 'runtime' => 'Runtime'), array(null, 'id')
262
     */
263 576
    protected static function getVariableName(&$context, $var, $lookup = null, $args = null) {
264 576
        if (isset($var[0]) && ($var[0] === Parser::LITERAL)) {
265 78
            if ($var[1] === "undefined") {
266 2
                $var[1] = "null";
267
            }
268 78
            return array($var[1], preg_replace('/\'(.*)\'/', '$1', $var[1]));
269
        }
270
271 538
        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...
272 538
        $exp = Expression::toString($levels, $spvar, $var);
273 538
        $base = $spvar ? "\$cx['sp_vars']" : '$in';
274
275
        // change base when trace to parent
276 538
        if ($levels > 0) {
277 39
            if ($spvar) {
278 2
                $base .= str_repeat("['_parent']", $levels);
279
            } else {
280 37
                $base = "\$cx['scopes'][count(\$cx['scopes'])-$levels]";
281
            }
282
        }
283
284 538
        if ((count($var) == 0) || (($var[0] === null) && (count($var) == 1))) {
285 134
            return array($base, $exp);
286
        }
287
288 481
        if ($var[0] === null) {
289 1
            array_shift($var);
290
        }
291
292
        // To support recursive context lookup, instance properties + methods and lambdas
293
        // the only way is using slower rendering time variable resolver.
294 481
        if ($context['flags']['prop'] || $context['flags']['method'] || $context['flags']['mustlok'] || $context['flags']['mustlam'] || $context['flags']['lambda']) {
295 383
            $L = $lookup ? ", $lookup[0]" : '';
296 383
            $A = $args ? ",$args[0]" : '';
297 383
            $E = $args ? ' ' . implode(' ', $args[1]) : '';
298 383
            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");
299
        }
300
301 99
        $n = Expression::arrayString($var);
302 99
        array_pop($var);
303 99
        $L = $lookup ? "[{$lookup[0]}]" : '';
304 99
        $p = $lookup ? $n : (count($var) ? Expression::arrayString($var) : '');
305
306 99
        return array("((isset($base$n$L) && is_array($base$p)) ? $base$n$L : " . ($context['flags']['debug'] ? (static::getFuncName($context, 'miss', '') . "\$cx, '$exp')") : 'null' ) . ')', $lookup ? "lookup $exp $lookup[1]" : $exp);
307
    }
308
309
    /**
310
     * Return compiled PHP code for a handlebars token
311
     *
312
     * @param array<string,array|string|integer> $context current compile context
313
     * @param array<string,array|boolean> $info parsed information
314
     *
315
     * @return string Return compiled code segment for the token
0 ignored issues
show
Documentation introduced by
Should the return type not be string|boolean|integer|double?

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...
316
     */
317 605
    protected static function compileToken(&$context, $info) {
318 605
        list($raw, $vars, $token, $indent) = $info;
319
320 605
        $context['tokens']['partialind'] = $indent;
321 605
        $context['currentToken'] = $token;
322
323
        // Do not touch the tag, keep it as is.
324 605
        if ($raw === -1) {
325
            return ".'" . Token::toString($token) . "'.";
326
        }
327
328 605
        if ($ret = static::operator($token[Token::POS_OP], $context, $vars)) {
329 371
            return $ret;
330
        }
331
332 469
        if (isset($vars[0][0])) {
333 437
            if ($ret = static::customHelper($context, $vars, $raw)) {
334 112
                return $ret;
335
            }
336 332
            if ($vars[0][0] === 'else') {
337 24
                return static::doElse($context);
338
            }
339 317
            if ($vars[0][0] === 'lookup') {
340 2
                return static::compileLookup($context, $vars, $raw);
341
            }
342
        }
343
344 354
        return static::compileVariable($context, $vars, $raw);
345
    }
346
347
    /**
348
     * handle partial
349
     *
350
     * @param array<string,array|string|integer> $context current compile context
351
     * @param array<boolean|integer|string|array> $vars parsed arguments list
352
     *
353
     * @return string Return compiled code segment for the partial
354
     */
355 85
    public static function partial(&$context, $vars) {
356
        // mustache spec: ignore missing partial
357 85
        if (($context['usedFeature']['dynpartial'] === 0) && ($context['usedFeature']['inlpartial'] === 0) && !isset($context['usedPartial'][$vars[0][0]])) {
358 1
            return $context['ops']['seperator'];
359
        }
360 84
        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...
361 84
        $p = array_shift($vars);
362 84
        if ($context['flags']['runpart']) {
363 77
            if (!isset($vars[0])) {
364 70
                $vars[0] = $context['flags']['partnc'] ? array(0, 'null') : array();
365
            }
366 77
            $v = static::getVariableNames($context, $vars);
367 77
            $tag = ">$p[0] " .implode(' ', $v[1]);
368 77
            if (Parser::isSubExp($p)) {
369 4
                list($p) = static::compileSubExpression($context, $p[1]);
370
            } else {
371 73
                $p = "'$p[0]'";
372
            }
373 77
            $sp = $context['tokens']['partialind'] ? ", '{$context['tokens']['partialind']}'" : '';
374 77
            return $context['ops']['seperator'] . static::getFuncName($context, 'p', $tag) . "\$cx, $p, $v[0]$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...
375
        }
376 7
        return "{$context['ops']['seperator']}'" . Partial::compileStatic($context, $p[0]) . "'{$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...
377
    }
378
379
    /**
380
     * handle inline partial
381
     *
382
     * @param array<string,array|string|integer> $context current compile context
383
     * @param array<boolean|integer|string|array> $vars parsed arguments list
384
     *
385
     * @return string Return compiled code segment for the partial
386
     */
387 10
    public static function inline(&$context, $vars) {
388 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...
389 10
        list($code) = array_shift($vars);
390 10
        $p = array_shift($vars);
391 10
        if (!isset($vars[0])) {
392 10
            $vars[0] = $context['flags']['partnc'] ? array(0, 'null') : array();
393
        }
394 10
        $v = static::getVariableNames($context, $vars);
395 10
        $tag = ">*inline $p[0]" .implode(' ', $v[1]);
396 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|null.

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...
397
    }
398
399
    /**
400
     * Return compiled PHP code for a handlebars inverted section begin token
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 token
406
     */
407 38
    protected static function invertedSection(&$context, $vars) {
408 38
        $v = static::getVariableName($context, $vars[0]);
409 38
        return "{$context['ops']['cnd_start']}(" . static::getFuncName($context, 'isec', '^' . $v[1]) . "\$cx, {$v[0]})){$context['ops']['cnd_then']}";
410
    }
411
412
    /**
413
     * Return compiled PHP code for a handlebars block custom helper begin token
414
     *
415
     * @param array<string,array|string|integer> $context current compile context
416
     * @param array<boolean|integer|string|array> $vars parsed arguments list
417
     * @param boolean $inverted the logic will be inverted
418
     *
419
     * @return string Return compiled code segment for the token
420
     */
421 61
    protected static function blockCustomHelper(&$context, $vars, $inverted = false) {
422 61
        $notHBCH = !isset($context['hbhelpers'][$vars[0][0]]);
423
424 61
        $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...
425 61
        $ch = array_shift($vars);
426 61
        $inverted = $inverted ? 'true' : 'false';
427 61
        static::addUsageCount($context, $notHBCH ? 'blockhelpers' : 'hbhelpers', $ch[0]);
428 61
        $v = static::getVariableNames($context, $vars, $bp);
429
430 61
        return $context['ops']['seperator'] . static::getFuncName($context, $notHBCH ? 'bch' : 'hbch', ($inverted ? '^' : '#') . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, \$in, $inverted, function(\$cx, \$in) {{$context['ops']['f_start']}";
431
    }
432
433
    /**
434
     * Return compiled PHP code for a handlebars block end token
435
     *
436
     * @param array<string,array|string|integer> $context current compile context
437
     * @param array<boolean|integer|string|array> $vars parsed arguments list
438
     * @param string|null $matchop should also match to this operator
439
     *
440
     * @return string Return compiled code segment for the token
441
     */
442 316
    protected static function blockEnd(&$context, $vars, $matchop = NULL) {
443 316
        $pop = $context['stack'][count($context['stack']) - 1];
444 316
        switch ($context['currentToken'][Token::POS_INNERTAG]) {
445
            case 'if':
446
            case 'unless':
447 69
                if ($pop === ':') {
448 19
                    array_pop($context['stack']);
449 19
                    return "{$context['ops']['cnd_end']}";
450
                }
451 50
                if (!$context['flags']['nohbh']) {
452 48
                    return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
453
                }
454 2
                break;
455 236
            case 'with':
456 32
                if (!$context['flags']['nohbh']) {
457 31
                    return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
458
                }
459
        }
460
461 239
        if ($pop === ':') {
462
            array_pop($context['stack']);
463
            return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
464
        }
465
466
        switch($pop) {
467 239
            case '#':
468 214
                return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
469
            case '^':
470 33
                return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
471
        }
472
    }
473
474
    /**
475
     * Return compiled PHP code for a handlebars block begin token
476
     *
477
     * @param array<string,array|string|integer> $context current compile context
478
     * @param array<boolean|integer|string|array> $vars parsed arguments list
479
     *
480
     * @return string Return compiled code segment for the token
481
     */
482 232
    protected static function blockBegin(&$context, $vars) {
483 232
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($context, $vars[1]) : array(null, array());
484 232
        if (!$context['flags']['nohbh']) {
485 194
            switch (isset($vars[0][0]) ? $vars[0][0] : null) {
486 4
                case 'if':
487 59
                    $includeZero = (isset($vars['includeZero'][1]) && $vars['includeZero'][1]) ? 'true' : 'false';
488 59
                    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...
489 4
                case 'unless':
490 3
                    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...
491 4
                case 'each':
492 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...
493 74
                case 'with':
494 27
                    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...
495 27
                        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...
496
                    }
497
            }
498
        }
499
500 112
        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...
501
    }
502
503
    /**
504
     * compile {{#foo}} token
505
     *
506
     * @param array<string,array|string|integer> $context current compile context
507
     * @param array<boolean|integer|string|array> $vars parsed arguments list
508
     * @param boolean $isEach the section is #each
509
     *
510
     * @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...
511
     */
512 159
    protected static function section(&$context, $vars, $isEach = false) {
513 159
        $bs = 'null';
514 159
        $be = '';
515 159
        if ($isEach) {
516 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...
517 47
            $bs = $bp ? ('array(' . Expression::listString($bp) . ')') : 'null';
518 47
            $be = $bp ? " as |$bp[0] $bp[1]|" : '';
519 47
            array_shift($vars);
520 47
            if (!isset($vars[0])) {
521
                $vars[0] = array(null);
522
            }
523
        }
524 159
        if ($context['flags']['lambda'] && !$isEach) {
525 66
            $V = array_shift($vars);
526 66
            $v = static::getVariableName($context, $V, null, count($vars) ? static::getVariableNames($context, $vars) : array('0',array('')));
527
        } else {
528 93
            $v = static::getVariableNameOrSubExpression($context, $vars[0]);
529
        }
530 159
        $each = $isEach ? 'true' : 'false';
531 159
        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...
532
    }
533
534
    /**
535
     * compile {{with}} token
536
     *
537
     * @param array<string,array|string|integer> $context current compile context
538
     * @param array<boolean|integer|string|array> $vars parsed arguments list
539
     *
540
     * @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...
541
     */
542 27
    protected static function with(&$context, $vars) {
543 27
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($context, $vars[1]) : array(null, array());
544 27
        $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...
545 27
        $bs = $bp ? ('array(' . Expression::listString($bp) . ')') : 'null';
546 27
        $be = $bp ? " as |$bp[0]|" : '';
547 27
        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...
548
    }
549
550
    /**
551
     * Return compiled PHP code for a handlebars custom helper 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
     * @param boolean $raw is this {{{ token or not
556
     *
557
     * @return string|null Return compiled code segment for the token when the token is custom helper
558
     */
559 445
    protected static function customHelper(&$context, $vars, $raw) {
560 445
        $notHH = !isset($context['hbhelpers'][$vars[0][0]]);
561 445
        if (!isset($context['helpers'][$vars[0][0]]) && $notHH) {
562 335
            return;
563
        }
564
565 123
        $fn = $raw ? 'raw' : $context['ops']['enc'];
566 123
        $ch = array_shift($vars);
567 123
        $v = static::getVariableNames($context, $vars);
568 123
        static::addUsageCount($context, $notHH ? 'helpers' : 'hbhelpers', $ch[0]);
569 123
        return $context['ops']['seperator'] . static::getFuncName($context, $notHH ? 'ch' : 'hbch', "$ch[0] " . implode(' ', $v[1])) . "\$cx, '$ch[0]', {$v[0]}, '$fn'" . ($notHH ? '' : ', $in') . "){$context['ops']['seperator']}";
570
    }
571
572
    /**
573
     * Return compiled PHP code for a handlebars else token
574
     *
575
     * @param array<string,array|string|integer> $context current compile context
576
     *
577
     * @return string Return compiled code segment for the token when the token is else
578
     */
579 46
    protected static function doElse(&$context) {
580 46
        switch ($context['stack'][count($context['stack']) - 2]) {
581
            case '[if]':
582 27
            case '[unless]':
583 19
                $context['stack'][] = ':';
584 19
                return "{$context['ops']['cnd_else']}";
585
            default:
586 27
                return "{$context['ops']['f_end']}}, function(\$cx, \$in) {{$context['ops']['f_start']}";
587
        }
588
    }
589
590
    /**
591
     * Return compiled PHP code for a handlebars lookup token
592
     *
593
     * @param array<string,array|string|integer> $context current compile context
594
     * @param array<boolean|integer|string|array> $vars parsed arguments list
595
     * @param boolean $raw is this {{{ token or not
596
     *
597
     * @return string Return compiled code segment for the token
598
     */
599 2
    protected static function compileLookup(&$context, &$vars, $raw) {
600 2
        $v2 = static::getVariableName($context, $vars[2]);
601 2
        $v = static::getVariableName($context, $vars[1], $v2);
0 ignored issues
show
Documentation introduced by
$v2 is of type array<integer,array|stri...teger,string>|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...
602 2
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug']) {
603 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...
604
        } else {
605
            return $raw ? "{$context['ops']['seperator']}$v[0]{$context['ops']['seperator']}" : "{$context['ops']['seperator']}htmlentities((string){$v[0]}, ENT_QUOTES, 'UTF-8'){$context['ops']['seperator']}";
606
        }
607
    }
608
609
    /**
610
     * Return compiled PHP code for a handlebars variable token
611
     *
612
     * @param array<string,array|string|integer> $context current compile context
613
     * @param array<boolean|integer|string|array> $vars parsed arguments list
614
     * @param boolean $raw is this {{{ token or not
615
     *
616
     * @return string Return compiled code segment for the token
617
     */
618 357
    protected static function compileVariable(&$context, &$vars, $raw) {
619 357
        if ($context['flags']['lambda']) {
620 224
            $V = array_shift($vars);
621 224
            $v = static::getVariableName($context, $V, null, count($vars) ? static::getVariableNames($context, $vars) : array('0',array('')));
622
        } else {
623 133
            $v = static::getVariableName($context, $vars[0]);
624
        }
625 357
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug']) {
626 322
            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...
627
        } else {
628 35
            return $raw ? "{$context['ops']['seperator']}$v[0]{$context['ops']['seperator']}" : "{$context['ops']['seperator']}htmlentities((string){$v[0]}, ENT_QUOTES, 'UTF-8'){$context['ops']['seperator']}";
629
        }
630
    }
631
632
    /**
633
     * Add usage count to context
634
     *
635
     * @param array<string,array|string|integer> $context current context
636
     * @param string $category ctegory name, can be one of: 'var', 'helpers', 'blockhelpers'
637
     * @param string $name used name
638
     * @param integer $count increment
639
     *
640
     * @expect 1 when input array('usedCount' => array('test' => array())), 'test', 'testname'
641
     * @expect 3 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname'
642
     * @expect 5 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname', 3
643
     */
644 581
    protected static function addUsageCount(&$context, $category, $name, $count = 1) {
645 581
        if (!isset($context['usedCount'][$category][$name])) {
646 581
            $context['usedCount'][$category][$name] = 0;
647
        }
648 581
        return ($context['usedCount'][$category][$name] += $count);
649
    }
650
}
651
652