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 ( 4347a7...178f3d )
by Zordius
02:13
created

Compiler::inline()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
ccs 3
cts 3
cp 1
rs 9.4286
cc 3
eloc 9
nc 3
nop 2
crap 3
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 702
    public static function compileTemplate(&$context, $template) {
44 702
        array_unshift($context['parsed'], array());
45 702
        Validator::verify($context, $template);
46
47 702
        if (count($context['error'])) {
48 69
            return;
49
        }
50
51
        // Do PHP code generation.
52 634
        Parser::setDelimiter($context);
53
54
        // Handle dynamic partials
55 634
        Partial::handleDynamicPartial($context);
56
57 634
        $code = '';
58 634
        foreach ($context['parsed'][0] as $info) {
59 634
            if (is_array($info)) {
60 593
                $context['tokens']['current']++;
61 593
                $tmpl = static::compileToken($context, $info);
62 593
                if ($tmpl == $context['ops']['seperator']) {
63 1
                    $tmpl = '';
64
                } else {
65 592
                    $tmpl = "'$tmpl'";
66
                }
67 593
                $code .= $tmpl;
68
            } else {
69 634
                $code .= $info;
70
            }
71
        }
72
73 634
        static::$lastParsed = array_shift($context['parsed']);
74
75 634
        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 633
    public static function composePHPRender($context, $code) {
87 633
        $flagJStrue = Expression::boolString($context['flags']['jstrue']);
88 633
        $flagJSObj = Expression::boolString($context['flags']['jsobj']);
89 633
        $flagSPVar = Expression::boolString($context['flags']['spvar']);
90 633
        $flagProp = Expression::boolString($context['flags']['prop']);
91 633
        $flagMethod = Expression::boolString($context['flags']['method']);
92 633
        $flagLambda = Expression::boolString($context['flags']['lambda']);
93 633
        $flagMustlok = Expression::boolString($context['flags']['mustlok']);
94 633
        $flagMustlam = Expression::boolString($context['flags']['mustlam']);
95 633
        $flagEcho = Expression::boolString($context['flags']['echo']);
96 633
        $flagPartNC = Expression::boolString($context['flags']['partnc']);
97 633
        $flagKnownHlp = Expression::boolString($context['flags']['knohlp']);
98
99 633
        $libstr = Exporter::runtime($context);
100 633
        $constants = Exporter::constants($context);
101 633
        $helpers = Exporter::helpers($context);
102 633
        $bhelpers = Exporter::helpers($context, 'blockhelpers');
103 633
        $hbhelpers = Exporter::helpers($context, 'hbhelpers');
104 633
        $debug = Runtime::DEBUG_ERROR_LOG;
105 633
        $phpstart = $context['flags']['bare'] ? '' : "<?php use {$context['runtime']} as LR;\n";
106 633
        $phpend = $context['flags']['bare'] ? ';' : "\n?>";
107
108
        // Return generated PHP code string.
109 633
        return "{$phpstart}return function (\$in, \$options = null) {
110
    \$cx = array(
111
        'flags' => array(
112
            'jstrue' => $flagJStrue,
113
            'jsobj' => $flagJSObj,
114
            'spvar' => $flagSPVar,
115
            'prop' => $flagProp,
116
            'method' => $flagMethod,
117
            'lambda' => $flagLambda,
118
            'mustlok' => $flagMustlok,
119
            'mustlam' => $flagMustlam,
120
            'echo' => $flagEcho,
121
            'partnc' => $flagPartNC,
122
            'knohlp' => $flagKnownHlp,
123
            'debug' => isset(\$options['debug']) ? \$options['debug'] : $debug,
124
        ),
125
        'constants' => $constants,
126
        'helpers' => $helpers,
127
        'blockhelpers' => $bhelpers,
128
        'hbhelpers' => isset(\$options['helpers']) ? array_merge($hbhelpers, \$options['helpers']) : $hbhelpers,
129 633
        'partials' => array({$context['partialCode']}),
130
        'scopes' => array(),
131
        'sp_vars' => isset(\$options['data']) ? array_merge(array('root' => \$in), \$options['data']) : array('root' => \$in),
132
        'blparam' => array(),
133 633
        'runtime' => '{$context['runtime']}',
134
$libstr
135
    );
136 633
    {$context['renderex']}
137 633
    {$context['ops']['op_start']}'$code'{$context['ops']['op_end']}
138 633
}$phpend";
139
    }
140
141
    /**
142
     * Get function name for standalone or none standalone template.
143
     *
144
     * @param array<string,array|string|integer> $context Current context of compiler progress.
145
     * @param string $name base function name
146
     * @param string $tag original handlabars tag for debug
147
     *
148
     * @return string compiled Function name
149
     *
150
     * @expect 'LR::test(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime'), 'test', ''
151
     * @expect 'LR::test2(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime'), 'test2', ''
152
     * @expect "\$cx['funcs']['test3'](" when input array('flags' => array('standalone' => 1, 'debug' => 0), 'runtime' => 'Runtime'), 'test3', ''
153
     * @expect 'LR::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1), 'runtime' => 'Runtime'), 'test', 'abc'
154
     */
155 569
    protected static function getFuncName(&$context, $name, $tag) {
156 569
        static::addUsageCount($context, 'runtime', $name);
157
158 569
        if ($context['flags']['debug'] && ($name != 'miss')) {
159 10
            $dbg = "'$tag', '$name', ";
160 10
            $name = 'debug';
161 10
            static::addUsageCount($context, 'runtime', 'debug');
162
        } else {
163 567
            $dbg = '';
164
        }
165
166 569
        return $context['flags']['standalone'] ? "\$cx['funcs']['$name']($dbg" : "LR::$name($dbg";
167
    }
168
169
    /**
170
     * Get string presentation of variables
171
     *
172
     * @param array<string,array|string|integer> $context current compile context
173
     * @param array<array> $vn variable name array.
174
     * @param array<string>|null $blockParams block param list
175
     *
176
     * @return array<string|array> variable names
177
     *
178
     * @expect array('array(array($in),array())', array('this')) when input array('flags'=>array('spvar'=>true)), array(null)
179
     * @expect array('array(array($in,$in),array())', array('this', 'this')) when input array('flags'=>array('spvar'=>true)), array(null, null)
180
     * @expect array('array(array(),array(\'a\'=>$in))', array('this')) when input array('flags'=>array('spvar'=>true)), array('a' => null)
181
     */
182 246
    protected static function getVariableNames(&$context, $vn, $blockParams = null) {
183 246
        $vars = array(array(), array());
184 246
        $exps = array();
185 246
        foreach ($vn as $i => $v) {
186 207
            $V = static::getVariableNameOrSubExpression($context, $v);
187 207
            if (is_string($i)) {
188 36
                $vars[1][] = "'$i'=>{$V[0]}";
189
            } else {
190 193
                $vars[0][] = $V[0];
191
            }
192 207
            $exps[] = $V[1];
193
        }
194 246
        $bp = $blockParams ? (',array(' . Expression::listString($blockParams) . ')') : '';
195 246
        return array('array(array(' . implode(',', $vars[0]) . '),array(' . implode(',', $vars[1]) . ")$bp)", $exps);
196
    }
197
198
    /**
199
     * Get string presentation of a sub expression
200
     *
201
     * @param array<string,array|string|integer> $context current compile context
202
     * @param array<boolean|integer|string|array> $vars parsed arguments list
203
     *
204
     * @return array<string> code representing passed expression
205
     */
206 41
    public static function compileSubExpression(&$context, $vars) {
207 41
        $origSeperator = $context['ops']['seperator'];
208 41
        $context['ops']['seperator'] = '';
209
210 41
        $ret = static::customHelper($context, $vars, true);
211
212 41
        if (($ret === null) && $context['flags']['lambda']) {
213 4
            $ret = static::compileVariable($context, $vars, true);
214
        }
215
216 41
        $context['ops']['seperator'] = $origSeperator;
217
218 41
        return array($ret ? $ret : '', 'FIXME: $subExpression');
219
    }
220
221
    /**
222
     * Get string presentation of a subexpression or a variable
223
     *
224
     * @param array<array|string|integer> $context current compile context
225
     * @param array<array|string|integer> $var variable parsed path
226
     *
227
     * @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...
228
     */
229 348
    protected static function getVariableNameOrSubExpression(&$context, $var) {
230 348
        return Parser::isSubExp($var) ? static::compileSubExpression($context, $var[1]) : static::getVariableName($context, $var);
231
    }
232
233
    /**
234
     * Get string presentation of a variable
235
     *
236
     * @param array<array|string|integer> $var variable parsed path
237
     * @param array<array|string|integer> $context current compile context
238
     * @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...
239
     *
240
     * @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...
241
     *
242
     * @expect array('$in', 'this') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(null)
243
     * @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')
244
     * @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')
245
     * @expect array('true', 'true') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'true')
246
     * @expect array('false', 'false') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, 'false')
247
     * @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')
248
     * @expect array('2', '2') when input array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0)), array(-1, '2')
249
     * @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')
250
     * @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')
251
     * @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')
252
     * @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')
253
     * @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')
254
     * @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"')
255
     * @expect array('"a"', '"a"') when input array('flags'=>array('spvar'=>true,'debug'=>0)), array(-1, '"a"')
256
     * @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')
257
     * @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')
258
     * @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')
259
     * @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')
260
     * @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')
261
     */
262 564
    protected static function getVariableName(&$context, $var, $lookup = null, $args = null) {
263 564
        if (isset($var[0]) && ($var[0] === Parser::LITERAL)) {
264 78
            if ($var[1] === "undefined") {
265 2
                $var[1] = "null";
266
            }
267 78
            return array($var[1], preg_replace('/\'(.*)\'/', '$1', $var[1]));
268
        }
269
270 526
        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...
271 526
        $exp = Expression::toString($levels, $spvar, $var);
272 526
        $base = $spvar ? "\$cx['sp_vars']" : '$in';
273
274
        // change base when trace to parent
275 526
        if ($levels > 0) {
276 39
            if ($spvar) {
277 2
                $base .= str_repeat("['_parent']", $levels);
278
            } else {
279 37
                $base = "\$cx['scopes'][count(\$cx['scopes'])-$levels]";
280
            }
281
        }
282
283 526
        if ((count($var) == 0) || (($var[0] === null) && (count($var) == 1))) {
284 122
            return array($base, $exp);
285
        }
286
287 481
        if ($var[0] === null) {
288 1
            array_shift($var);
289
        }
290
291
        // To support recursive context lookup, instance properties + methods and lambdas
292
        // the only way is using slower rendering time variable resolver.
293 481
        if ($context['flags']['prop'] || $context['flags']['method'] || $context['flags']['mustlok'] || $context['flags']['mustlam'] || $context['flags']['lambda']) {
294 383
            $L = $lookup ? ", $lookup[0]" : '';
295 383
            $A = $args ? ",$args[0]" : '';
296 383
            $E = $args ? ' ' . implode(' ', $args[1]) : '';
297 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");
298
        }
299
300 99
        $n = Expression::arrayString($var);
301 99
        array_pop($var);
302 99
        $L = $lookup ? "[{$lookup[0]}]" : '';
303 99
        $p = $lookup ? $n : (count($var) ? Expression::arrayString($var) : '');
304
305 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);
306
    }
307
308
    /**
309
     * Return compiled PHP code for a handlebars token
310
     *
311
     * @param array<string,array|string|integer> $context current compile context
312
     * @param array<string,array|boolean> $info parsed information
313
     *
314
     * @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...
315
     */
316 593
    protected static function compileToken(&$context, $info) {
317 593
        list($raw, $vars, $token, $indent) = $info;
318
319 593
        $context['tokens']['partialind'] = $indent;
320 593
        $context['currentToken'] = $token;
321
322
        // Do not touch the tag, keep it as is.
323 593
        if ($raw === -1) {
324
            return ".'" . Token::toString($token) . "'.";
325
        }
326
327 593
        if ($ret = static::operator($token[Token::POS_OP], $context, $vars)) {
328 359
            return $ret;
329
        }
330
331 469
        if (isset($vars[0][0])) {
332 437
            if ($ret = static::customHelper($context, $vars, $raw)) {
333 112
                return $ret;
334
            }
335 332
            if ($vars[0][0] === 'else') {
336 24
                return static::doElse($context);
337
            }
338 317
            if ($vars[0][0] === 'lookup') {
339 2
                return static::compileLookup($context, $vars, $raw);
340
            }
341
        }
342
343 354
        return static::compileVariable($context, $vars, $raw);
344
    }
345
346
    /**
347
     * handle partial
348
     *
349
     * @param array<string,array|string|integer> $context current compile context
350
     * @param array<boolean|integer|string|array> $vars parsed arguments list
351
     *
352
     * @return string Return compiled code segment for the partial
353
     */
354 73
    public static function partial(&$context, $vars) {
355
        // mustache spec: ignore missing partial
356 73
        if (($context['usedFeature']['dynpartial'] === 0) && ($context['usedFeature']['inlpartial'] === 0) && !isset($context['usedPartial'][$vars[0][0]])) {
357 1
            return $context['ops']['seperator'];
358
        }
359 72
        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...
360 72
        $p = array_shift($vars);
361 72
        if ($context['flags']['runpart']) {
362 65
            if (!isset($vars[0])) {
363 58
                $vars[0] = $context['flags']['partnc'] ? array(0, 'null') : array();
364
            }
365 65
            $v = static::getVariableNames($context, $vars);
366 65
            $tag = ">$p[0] " .implode(' ', $v[1]);
367 65
            if (Parser::isSubExp($p)) {
368 4
                list($p) = static::compileSubExpression($context, $p[1]);
369
            } else {
370 61
                $p = "'$p[0]'";
371
            }
372 65
            $sp = $context['tokens']['partialind'] ? ", '{$context['tokens']['partialind']}'" : '';
373 65
            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...
374
        }
375 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...
376
    }
377
378
    /**
379
     * handle inline partial
380
     *
381
     * @param array<string,array|string|integer> $context current compile context
382
     * @param array<boolean|integer|string|array> $vars parsed arguments list
383
     *
384
     * @return string Return compiled code segment for the partial
385
     */
386 38
    public static function inline(&$context, $vars) {
387 38
        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...
388 38
        list($code) = array_shift($vars);
389
        $p = array_shift($vars);
390
        if (!isset($vars[0])) {
391
            $vars[0] = $context['flags']['partnc'] ? array(0, 'null') : array();
392
        }
393
        $v = static::getVariableNames($context, $vars);
394
        $tag = ">*inline $p[0]" .implode(' ', $v[1]);
395
        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...
396
    }
397
398
    /**
399
     * Return compiled PHP code for a handlebars inverted section begin token
400 61
     *
401 61
     * @param array<string,array|string|integer> $context current compile context
402
     * @param array<boolean|integer|string|array> $vars parsed arguments list
403 61
     *
404 61
     * @return string Return compiled code segment for the token
405 61
     */
406 61
    protected static function invertedSection(&$context, $vars) {
407 61
        $v = static::getVariableName($context, $vars[0]);
408
        return "{$context['ops']['cnd_start']}(" . static::getFuncName($context, 'isec', '^' . $v[1]) . "\$cx, {$v[0]})){$context['ops']['cnd_then']}";
409 61
    }
410
411
    /**
412
     * Return compiled PHP code for a handlebars block custom helper begin token
413
     *
414
     * @param array<string,array|string|integer> $context current compile context
415
     * @param array<boolean|integer|string|array> $vars parsed arguments list
416
     * @param boolean $inverted the logic will be inverted
417
     *
418
     * @return string Return compiled code segment for the token
419
     */
420 313
    protected static function blockCustomHelper(&$context, $vars, $inverted = false) {
421 313
        $notHBCH = !isset($context['hbhelpers'][$vars[0][0]]);
422 313
423
        $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...
424
        $ch = array_shift($vars);
425 69
        $inverted = $inverted ? 'true' : 'false';
426 19
        static::addUsageCount($context, $notHBCH ? 'blockhelpers' : 'hbhelpers', $ch[0]);
427 19
        $v = static::getVariableNames($context, $vars, $bp);
428
429 50
        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']}";
430 48
    }
431
432 2
    /**
433 236
     * Return compiled PHP code for a handlebars block end token
434 29
     *
435 28
     * @param array<string,array|string|integer> $context current compile context
436
     * @param array<boolean|integer|string|array> $vars parsed arguments list
437
     *
438
     * @return string Return compiled code segment for the token
439 239
     */
440
    protected static function blockEnd(&$context, $vars) {
441
        $pop = $context['stack'][count($context['stack']) - 1];
442
        switch ($context['currentToken'][Token::POS_INNERTAG]) {
443
            case 'if':
444
            case 'unless':
445 239
                if ($pop === ':') {
446 214
                    array_pop($context['stack']);
447
                    return "{$context['ops']['cnd_end']}";
448 33
                }
449
                if (!$context['flags']['nohbh']) {
450
                    return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
451
                }
452
                break;
453
            case 'with':
454
                if (!$context['flags']['nohbh']) {
455
                    return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
456
                }
457
        }
458
459
        if ($pop === ':') {
460 229
            array_pop($context['stack']);
461 229
            return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
462 229
        }
463 191
464 4
        switch($pop) {
465 59
            case '#':
466 59
                return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
467 4
            case '^':
468 3
                return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
469 4
        }
470 47
    }
471 74
472 24
    /**
473 24
     * Return compiled PHP code for a handlebars block begin token
474
     *
475
     * @param array<string,array|string|integer> $context current compile context
476
     * @param array<boolean|integer|string|array> $vars parsed arguments list
477
     *
478 112
     * @return string Return compiled code segment for the token
479
     */
480
    protected static function blockBegin(&$context, $vars) {
481
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($context, $vars[1]) : array(null, array());
482
        if (!$context['flags']['nohbh']) {
483
            switch (isset($vars[0][0]) ? $vars[0][0] : null) {
484
                case 'if':
485
                    $includeZero = (isset($vars['includeZero'][1]) && $vars['includeZero'][1]) ? 'true' : 'false';
486
                    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...
487
                case 'unless':
488
                    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...
489
                case 'each':
490 159
                    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...
491 159
                case 'with':
492 159
                    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...
493 159
                        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...
494 47
                    }
495 47
            }
496 47
        }
497 47
498 47
        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...
499
    }
500
501
    /**
502 159
     * compile {{#foo}} token
503 66
     *
504 66
     * @param array<string,array|string|integer> $context current compile context
505
     * @param array<boolean|integer|string|array> $vars parsed arguments list
506 93
     * @param boolean $isEach the section is #each
507
     *
508 159
     * @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...
509 159
     */
510
    protected static function section(&$context, $vars, $isEach = false) {
511
        $bs = 'null';
512
        $be = '';
513
        if ($isEach) {
514
            $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...
515
            $bs = $bp ? ('array(' . Expression::listString($bp) . ')') : 'null';
516
            $be = $bp ? " as |$bp[0] $bp[1]|" : '';
517
            array_shift($vars);
518
            if (!isset($vars[0])) {
519
                $vars[0] = array(null);
520 24
            }
521 24
        }
522 24
        if ($context['flags']['lambda'] && !$isEach) {
523 24
            $V = array_shift($vars);
524 24
            $v = static::getVariableName($context, $V, null, count($vars) ? static::getVariableNames($context, $vars) : array('0',array('')));
525 24
        } else {
526
            $v = static::getVariableNameOrSubExpression($context, $vars[0]);
527
        }
528
        $each = $isEach ? 'true' : 'false';
529
        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...
530
    }
531
532
    /**
533
     * compile {{with}} token
534
     *
535
     * @param array<string,array|string|integer> $context current compile context
536
     * @param array<boolean|integer|string|array> $vars parsed arguments list
537 445
     *
538 445
     * @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...
539 445
     */
540 335
    protected static function with(&$context, $vars) {
541
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($context, $vars[1]) : array(null, array());
542
        $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...
543 123
        $bs = $bp ? ('array(' . Expression::listString($bp) . ')') : 'null';
544 123
        $be = $bp ? " as |$bp[0]|" : '';
545 123
        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...
546 123
    }
547 123
548
    /**
549
     * Return compiled PHP code for a handlebars custom helper token
550
     *
551
     * @param array<string,array|string|integer> $context current compile context
552
     * @param array<boolean|integer|string|array> $vars parsed arguments list
553
     * @param boolean $raw is this {{{ token or not
554
     *
555
     * @return string|null Return compiled code segment for the token when the token is custom helper
556
     */
557 46
    protected static function customHelper(&$context, $vars, $raw) {
558 46
        $notHH = !isset($context['hbhelpers'][$vars[0][0]]);
559
        if (!isset($context['helpers'][$vars[0][0]]) && $notHH) {
560 27
            return;
561 19
        }
562 19
563
        $fn = $raw ? 'raw' : $context['ops']['enc'];
564 27
        $ch = array_shift($vars);
565
        $v = static::getVariableNames($context, $vars);
566
        static::addUsageCount($context, $notHH ? 'helpers' : 'hbhelpers', $ch[0]);
567
        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']}";
568
    }
569
570
    /**
571
     * Return compiled PHP code for a handlebars else token
572
     *
573
     * @param array<string,array|string|integer> $context current compile context
574
     *
575
     * @return string Return compiled code segment for the token when the token is else
576
     */
577 2
    protected static function doElse(&$context) {
578 2
        switch ($context['stack'][count($context['stack']) - 2]) {
579 2
            case '[if]':
580 2
            case '[unless]':
581 2
                $context['stack'][] = ':';
582
                return "{$context['ops']['cnd_else']}";
583
            default:
584
                return "{$context['ops']['f_end']}}, function(\$cx, \$in) {{$context['ops']['f_start']}";
585
        }
586
    }
587
588
    /**
589
     * Return compiled PHP code for a handlebars lookup token
590
     *
591
     * @param array<string,array|string|integer> $context current compile context
592
     * @param array<boolean|integer|string|array> $vars parsed arguments list
593
     * @param boolean $raw is this {{{ token or not
594
     *
595
     * @return string Return compiled code segment for the token
596 357
     */
597 357
    protected static function compileLookup(&$context, &$vars, $raw) {
598 224
        $v2 = static::getVariableName($context, $vars[2]);
599 224
        $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...
600
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug']) {
601 133
            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...
602
        } else {
603 357
            return $raw ? "{$context['ops']['seperator']}$v[0]{$context['ops']['seperator']}" : "{$context['ops']['seperator']}htmlentities((string){$v[0]}, ENT_QUOTES, 'UTF-8'){$context['ops']['seperator']}";
604 322
        }
605
    }
606 35
607
    /**
608
     * Return compiled PHP code for a handlebars variable token
609
     *
610
     * @param array<string,array|string|integer> $context current compile context
611
     * @param array<boolean|integer|string|array> $vars parsed arguments list
612
     * @param boolean $raw is this {{{ token or not
613
     *
614
     * @return string Return compiled code segment for the token
615
     */
616
    protected static function compileVariable(&$context, &$vars, $raw) {
617
        if ($context['flags']['lambda']) {
618
            $V = array_shift($vars);
619
            $v = static::getVariableName($context, $V, null, count($vars) ? static::getVariableNames($context, $vars) : array('0',array('')));
620
        } else {
621
            $v = static::getVariableName($context, $vars[0]);
622 569
        }
623 569
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug']) {
624 569
            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...
625
        } else {
626 569
            return $raw ? "{$context['ops']['seperator']}$v[0]{$context['ops']['seperator']}" : "{$context['ops']['seperator']}htmlentities((string){$v[0]}, ENT_QUOTES, 'UTF-8'){$context['ops']['seperator']}";
627
        }
628
    }
629
630
    /**
631
     * Add usage count to context
632
     *
633
     * @param array<string,array|string|integer> $context current context
634
     * @param string $category ctegory name, can be one of: 'var', 'helpers', 'blockhelpers'
635
     * @param string $name used name
636
     * @param integer $count increment
637
     *
638
     * @expect 1 when input array('usedCount' => array('test' => array())), 'test', 'testname'
639
     * @expect 3 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname'
640
     * @expect 5 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname', 3
641
     */
642
    protected static function addUsageCount(&$context, $category, $name, $count = 1) {
643
        if (!isset($context['usedCount'][$category][$name])) {
644
            $context['usedCount'][$category][$name] = 0;
645
        }
646
        return ($context['usedCount'][$category][$name] += $count);
647
    }
648
}
649
650