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 ( 8b9a0e...e02b63 )
by Zordius
02:44
created

Compiler::compileLookup()   B

Complexity

Conditions 7
Paths 3

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 7.227

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
ccs 5
cts 6
cp 0.8333
rs 8.2222
cc 7
eloc 7
nc 3
nop 3
crap 7.227
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
27
/**
28
 * LightnCandy Compiler
29
 */
30
class Compiler extends Validator
31
{
32
    public static $lastParsed;
33
34
    /**
35
     * Compile template into PHP code
36
     *
37
     * @param array<string,array|string|integer> $context Current context
38
     * @param string $template handlebars template
39
     *
40
     * @return string|null generated PHP code
41
     */
42 630
    public static function compileTemplate(&$context, $template) {
43 630
        array_unshift($context['parsed'], array());
44 630
        Validator::verify($context, $template);
45
46 630
        if (count($context['error'])) {
47 64
            return;
48
        }
49
50
        // Do PHP code generation.
51 567
        Parser::setDelimiter($context);
52
53
        // Handle dynamic partials
54 567
        Partial::handleDynamicPartial($context);
55
56 567
        $code = '';
57 567
        foreach ($context['parsed'][0] as $info) {
58 567
            if (is_array($info)) {
59 526
                $context['tokens']['current']++;
60 526
                $tmpl = static::compileToken($info, $context);
61 526
                if ($tmpl == $context['ops']['seperator']) {
62 1
                    $tmpl = '';
63 1
                } else {
64 525
                    $tmpl = "'$tmpl'";
65
                }
66 526
                $code .= $tmpl;
67 526
            } else {
68 411
                $code .= $info;
69
            }
70 567
        }
71
72 567
        static::$lastParsed = array_shift($context['parsed']);
73
74 567
        return $code;
75
    }
76
77
    /**
78
     * Compose LightnCandy render codes for include()
79
     *
80
     * @param array<string,array|string|integer> $context Current context
81
     * @param string $code generated PHP code
82
     *
83
     * @return string Composed PHP code
84
     */
85 566
    public static function composePHPRender($context, $code) {
86 566
        $flagJStrue = Expression::boolString($context['flags']['jstrue']);
87 566
        $flagJSObj = Expression::boolString($context['flags']['jsobj']);
88 566
        $flagSPVar = Expression::boolString($context['flags']['spvar']);
89 566
        $flagProp = Expression::boolString($context['flags']['prop']);
90 566
        $flagMethod = Expression::boolString($context['flags']['method']);
91 566
        $flagLambda = Expression::boolString($context['flags']['lambda']);
92 566
        $flagMustlok = Expression::boolString($context['flags']['mustlok']);
93 566
        $flagMustlam = Expression::boolString($context['flags']['mustlam']);
94 566
        $flagEcho = Expression::boolString($context['flags']['echo']);
95
96 566
        $libstr = Exporter::runtime($context);
97 566
        $constants = Exporter::constants($context);
98 566
        $helpers = Exporter::helpers($context);
99 566
        $bhelpers = Exporter::helpers($context, 'blockhelpers');
100 566
        $hbhelpers = Exporter::helpers($context, 'hbhelpers');
101 566
        $debug = Runtime::DEBUG_ERROR_LOG;
102 566
        $phpstart = $context['flags']['bare'] ? '' : "<?php use {$context['runtime']} as LR;\n";
103 566
        $phpend = $context['flags']['bare'] ? ';' : "\n?>";
104
105
        // Return generated PHP code string.
106 566
        return "{$phpstart}return function (\$in, \$options = null) {
107
    \$cx = array(
108
        'flags' => array(
109 566
            'jstrue' => $flagJStrue,
110 566
            'jsobj' => $flagJSObj,
111 566
            'spvar' => $flagSPVar,
112 566
            'prop' => $flagProp,
113 566
            'method' => $flagMethod,
114 566
            'lambda' => $flagLambda,
115 566
            'mustlok' => $flagMustlok,
116 566
            'mustlam' => $flagMustlam,
117 566
            'echo' => $flagEcho,
118 566
            'debug' => isset(\$options['debug']) ? \$options['debug'] : $debug,
119
        ),
120 566
        'constants' => $constants,
121 566
        'helpers' => $helpers,
122 566
        'blockhelpers' => $bhelpers,
123 566
        'hbhelpers' => isset(\$options['helpers']) ? array_merge($hbhelpers, \$options['helpers']) : $hbhelpers,
124 566
        'partials' => array({$context['partialCode']}),
125
        'scopes' => array(),
126
        'sp_vars' => isset(\$options['data']) ? array_merge(array('root' => \$in), \$options['data']) : array('root' => \$in),
127 566
        'runtime' => '{$context['runtime']}',
128 566
$libstr
129
    );
130 566
    {$context['renderex']}
131 566
    {$context['ops']['op_start']}'$code'{$context['ops']['op_end']}
132 566
}$phpend";
133
    }
134
135
    /**
136
     * Get function name for standalone or none standalone template.
137
     *
138
     * @param array<string,array|string|integer> $context Current context of compiler progress.
139
     * @param string $name base function name
140
     * @param string $tag original handlabars tag for debug
141
     *
142
     * @return string compiled Function name
143
     *
144
     * @expect 'LR::test(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime'), 'test', ''
145
     * @expect 'LR::test2(' when input array('flags' => array('standalone' => 0, 'debug' => 0), 'runtime' => 'Runtime'), 'test2', ''
146
     * @expect "\$cx['funcs']['test3'](" when input array('flags' => array('standalone' => 1, 'debug' => 0), 'runtime' => 'Runtime'), 'test3', ''
147
     * @expect 'LR::debug(\'abc\', \'test\', ' when input array('flags' => array('standalone' => 0, 'debug' => 1), 'runtime' => 'Runtime'), 'test', 'abc'
148
     */
149 502
    protected static function getFuncName(&$context, $name, $tag) {
150 502
        static::addUsageCount($context, 'runtime', $name);
151
152 502
        if ($context['flags']['debug'] && ($name != 'miss')) {
153 10
            $dbg = "'$tag', '$name', ";
154 10
            $name = 'debug';
155 10
            static::addUsageCount($context, 'runtime', 'debug');
156 10
        } else {
157 500
            $dbg = '';
158
        }
159
160 502
        return $context['flags']['standalone'] ? "\$cx['funcs']['$name']($dbg" : "LR::$name($dbg";
161
    }
162
163
    /**
164
     * Get string presentation of variables
165
     *
166
     * @param array<array> $vn variable name array.
167
     * @param array<string,array|string|integer> $context current compile context
168
     *
169
     * @return array<string|array> variable names
170
     *
171
     * @expect array('array(array($in),array())', array('this')) when input array(null), array('flags'=>array('spvar'=>true))
172
     * @expect array('array(array($in,$in),array())', array('this', 'this')) when input array(null, null), array('flags'=>array('spvar'=>true))
173
     * @expect array('array(array(),array(\'a\'=>$in))', array('this')) when input array('a' => null), array('flags'=>array('spvar'=>true))
174
     */
175 210
    protected static function getVariableNames($vn, &$context) {
176 210
        $vars = array(array(), array());
177 210
        $exps = array();
178 210
        foreach ($vn as $i => $v) {
179 175
            $V = static::getVariableNameOrSubExpression($v, $context);
180 175
            if (is_string($i)) {
181 28
                $vars[1][] = "'$i'=>{$V[0]}";
182 28
            } else {
183 162
                $vars[0][] = $V[0];
184
            }
185 175
            $exps[] = $V[1];
186 210
        }
187 210
        return array('array(array(' . implode(',', $vars[0]) . '),array(' . implode(',', $vars[1]) . '))', $exps);
188
    }
189
190
    /**
191
     * Get string presentation of a sub expression
192
     *
193
     * @param array<boolean|integer|string|array> $vars parsed arguments list
194
     * @param array<string,array|string|integer> $context current compile context
195
     *
196
     * @return array<string> code representing passed expression
197
     */
198 35
    public static function compileSubExpression($vars, &$context) {
199 35
        $origSeperator = $context['ops']['seperator'];
200 35
        $context['ops']['seperator'] = '';
201
202 35
        $ret = static::customHelper($context, $vars, true);
203
204 35
        if (($ret === null) && $context['flags']['lambda']) {
205 2
            $ret = static::compileVariable($context, $vars, true);
206 2
        }
207
208 35
        $context['ops']['seperator'] = $origSeperator;
209
210 35
        return array($ret ? $ret : '', 'FIXME: $subExpression');
211
    }
212
213
    /**
214
     * Get string presentation of a subexpression or a variable
215
     *
216
     * @param array<array|string|integer> $var variable parsed path
217
     * @param array<array|string|integer> $context current compile context
218
     *
219
     * @return array<string> variable names
220
     */
221 341
    protected static function getVariableNameOrSubExpression($var, &$context) {
222 341
        return Parser::isSubexp($var) ? static::compileSubExpression($var[1], $context) : static::getVariableName($var, $context);
223
    }
224
225
    /**
226
     * Get string presentation of a variable
227
     *
228
     * @param array<array|string|integer> $var variable parsed path
229
     * @param array<array|string|integer> $context current compile context
230
     * @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...
231
     *
232
     * @return array<string> variable names
233
     *
234
     * @expect array('$in', 'this') when input array(null), array('flags'=>array('spvar'=>true,'debug'=>0))
235
     * @expect array('((isset($in[\'true\']) && is_array($in)) ? $in[\'true\'] : null)', '[true]') when input array('true'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
236
     * @expect array('((isset($in[\'false\']) && is_array($in)) ? $in[\'false\'] : null)', '[false]') when input array('false'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
237
     * @expect array('true', 'true') when input array(0, 'true'), array('flags'=>array('spvar'=>true,'debug'=>0))
238
     * @expect array('false', 'false') when input array(0, 'false'), array('flags'=>array('spvar'=>true,'debug'=>0))
239
     * @expect array('((isset($in[\'2\']) && is_array($in)) ? $in[\'2\'] : null)', '[2]') when input array('2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
240
     * @expect array('2', '2') when input array(0, '2'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0))
241
     * @expect array('((isset($in[\'@index\']) && is_array($in)) ? $in[\'@index\'] : null)', '[@index]') when input array('@index'), array('flags'=>array('spvar'=>false,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
242
     * @expect array("((isset(\$cx['sp_vars']['index']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['index'] : null)", '@[index]') when input array('@index'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
243
     * @expect array("((isset(\$cx['sp_vars']['key']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['key'] : null)", '@[key]') when input array('@key'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
244
     * @expect array("((isset(\$cx['sp_vars']['first']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['first'] : null)", '@[first]') when input array('@first'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
245
     * @expect array("((isset(\$cx['sp_vars']['last']) && is_array(\$cx['sp_vars'])) ? \$cx['sp_vars']['last'] : null)", '@[last]') when input array('@last'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
246
     * @expect array('((isset($in[\'"a"\']) && is_array($in)) ? $in[\'"a"\'] : null)', '["a"]') when input array('"a"'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
247
     * @expect array('"a"', '"a"') when input array(0, '"a"'), array('flags'=>array('spvar'=>true,'debug'=>0))
248
     * @expect array('((isset($in[\'a\']) && is_array($in)) ? $in[\'a\'] : null)', '[a]') when input array('a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
249
     * @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(1,'a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
250
     * @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(3,'a'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
251
     * @expect array('((isset($in[\'id\']) && is_array($in)) ? $in[\'id\'] : null)', 'this.[id]') when input array(null, 'id'), array('flags'=>array('spvar'=>true,'debug'=>0,'prop'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0))
252
     * @expect array('LR::v($cx, isset($in) ? $in : null, array(\'id\'))', 'this.[id]') when input array(null, 'id'), array('flags'=>array('prop'=>true,'spvar'=>true,'debug'=>0,'method'=>0,'mustlok'=>0,'mustlam'=>0, 'lambda'=>0,'standalone'=>0), 'runtime' => 'Runtime')
253
     */
254 502
    protected static function getVariableName($var, &$context, $lookup = null) {
255 502
        if (isset($var[0]) && ($var[0] === 0)) {
256 60
            return array($var[1], preg_replace('/\'(.*)\'/', '$1', $var[1]));
257
        }
258
259 475
        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...
260 475
        $exp = Expression::toString($levels, $spvar, $var);
261 475
        $base = $spvar ? "\$cx['sp_vars']" : '$in';
262
263
        // change base when trace to parent
264 475
        if ($levels > 0) {
265 35
            if ($spvar) {
266 2
                $base .= str_repeat("['_parent']", $levels);
267 2
            } else {
268 33
                $base = "\$cx['scopes'][count(\$cx['scopes'])-$levels]";
269
            }
270 35
        }
271
272 475
        if ((count($var) == 0) || (($var[0] === null) && (count($var) == 1))) {
273 118
            return array($base, $exp);
274
        }
275
276 430
        if ($var[0] === null) {
277 1
            array_shift($var);
278 1
        }
279
280
        // To support recursive context lookup, instance properties + methods and lambdas
281
        // the only way is using slower rendering time variable resolver.
282 430
        if ($context['flags']['prop'] || $context['flags']['method'] || $context['flags']['mustlok'] || $context['flags']['mustlam'] || $context['flags']['lambda']) {
283 332
            $L = $lookup ? ", $lookup[0]" : '';
284 332
            return array(static::getFuncName($context, 'v', $exp) . "\$cx, isset($base) ? $base : null, array(" . implode(',', array_map(function ($V) {
285 332
                return "'$V'";
286 332
            }, $var)) . "$L))", $lookup ? "lookup $exp $lookup[1]" : $exp);
287
        }
288
289 99
        $n = Expression::arrayString($var);
290 99
        array_pop($var);
291 99
        $L = $lookup ? "[{$lookup[0]}]" : '';
292 99
        $p = $lookup ? $n : (count($var) ? Expression::arrayString($var) : '');
293
294 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);
295
    }
296
297
    /**
298
     * Return compiled PHP code for a handlebars token
299
     *
300
     * @param array<string,array|boolean> $info parsed information
301
     * @param array<string,array|string|integer> $context current compile context
302
     *
303
     * @return string Return compiled code segment for the token
0 ignored issues
show
Documentation introduced by
Should the return type not be string|integer|double|boolean?

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...
304
     */
305 526
    protected static function compileToken($info, &$context) {
306 526
        list($raw, $vars, $token, $indent) = $info;
307
308 526
        $context['tokens']['partialind'] = $indent;
309 526
        $context['currentToken'] = $token;
310
311
        // Do not touch the tag, keep it as is.
312 526
        if ($raw === -1) {
313
            return ".'" . Token::toString($token) . "'.";
314
        }
315
316 526
        if ($ret = static::operator($token[Token::POS_OP], $context, $vars)) {
317 320
            return $ret;
318
        }
319
320 412
        if (isset($vars[0][0])) {
321 381
            if ($ret = static::customHelper($context, $vars, $raw)) {
322 96
                return $ret;
323
            }
324 290
            if ($vars[0][0] === 'else') {
325 24
                return static::doElse($context);
326
            }
327 275
            if ($vars[0][0] === 'lookup') {
328 2
                return static::compileLookup($context, $vars, $raw);
329
            }
330 273
        }
331
332 311
        return static::compileVariable($context, $vars, $raw);
333
    }
334
335
    /**
336
     * handle partial
337
     *
338
     * @param array<string,array|string|integer> $context current compile context
339
     * @param array<boolean|integer|string|array> $vars parsed arguments list
340
     *
341
     * @return string Return compiled code segment for the partial
342
     */
343 62
    public static function partial(&$context, $vars) {
344
        // mustache spec: ignore missing partial
345 62
        if (($context['usedFeature']['dynpartial'] === 0) && !isset($context['usedPartial'][$vars[0][0]])) {
346 1
            return $context['ops']['seperator'];
347
        }
348 61
        $p = array_shift($vars);
349 61
        if (!isset($vars[0])) {
350 55
            $vars[0] = array();
351 55
        }
352 61
        $v = static::getVariableNames($vars, $context);
353 61
        $tag = ">$p[0] " .implode(' ', $v[1]);
354 61
        if ($context['flags']['runpart']) {
355 54
            if (Parser::isSubexp($p)) {
356 4
                list($p) = static::compileSubExpression($p[1], $context);
357 4
            } else {
358 50
                $p = "'$p[0]'";
359
            }
360 54
            $sp = $context['tokens']['partialind'] ? ", '{$context['tokens']['partialind']}'" : '';
361 54
            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...
362
        }
363 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...
364
    }
365
366
    /**
367
     * Return compiled PHP code for a handlebars inverted section begin token
368
     *
369
     * @param array<string,array|string|integer> $context current compile context
370
     * @param array<boolean|integer|string|array> $vars parsed arguments list
371
     *
372
     * @return string Return compiled code segment for the token
373
     */
374 37
    protected static function invertedSection(&$context, $vars) {
375 37
        $v = static::getVariableName($vars[0], $context);
376 37
        return "{$context['ops']['cnd_start']}(" . static::getFuncName($context, 'isec', '^' . $v[1]) . "\$cx, {$v[0]})){$context['ops']['cnd_then']}";
377
    }
378
379
    /**
380
     * Return compiled PHP code for a handlebars block custom helper begin token
381
     *
382
     * @param array<string,array|string|integer> $context current compile context
383
     * @param array<boolean|integer|string|array> $vars parsed arguments list
384
     * @param boolean $inverted the logic will be inverted
385
     *
386
     * @return string Return compiled code segment for the token
387
     */
388 52
    protected static function blockCustomHelper(&$context, $vars, $inverted = false) {
389 52
        $notHBCH = !isset($context['hbhelpers'][$vars[0][0]]);
390
391 52
        $ch = array_shift($vars);
392 52
        $inverted = $inverted ? 'true' : 'false';
393
394 52
        static::addUsageCount($context, $notHBCH ? 'blockhelpers' : 'hbhelpers', $ch[0]);
395 52
        $v = static::getVariableNames($vars, $context);
396 52
        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']}";
397
    }
398
399
    /**
400
     * Return compiled PHP code for a handlebars block end 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 279
    protected static function blockEnd(&$context, $vars) {
408 279
        $pop = $context['stack'][count($context['stack']) - 1];
409 279
        switch ($context['currentToken'][Token::POS_INNERTAG]) {
410 279
            case 'if':
411 279
            case 'unless':
412 64
                if ($pop === ':') {
413 19
                    array_pop($context['stack']);
414 19
                    return "{$context['ops']['cnd_end']}";
415
                }
416 45
                if (!$context['flags']['nohbh']) {
417 43
                    return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
418
                }
419 2
                break;
420 229
            case 'with':
421 16
                if (!$context['flags']['nohbh']) {
422 15
                    return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
423
                }
424 220
        }
425
426 220
        if ($pop === ':') {
427
            array_pop($context['stack']);
428
            return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
429
        }
430
431
        switch($pop) {
432 220
            case '#':
433 196
                return "{$context['ops']['f_end']}}){$context['ops']['seperator']}";
434 32
            case '^':
435 32
                return "{$context['ops']['cnd_else']}''{$context['ops']['cnd_end']}";
436
        }
437
    }
438
439
    /**
440
     * Return compiled PHP code for a handlebars block begin token
441
     *
442
     * @param array<string,array|string|integer> $context current compile context
443
     * @param array<boolean|integer|string|array> $vars parsed arguments list
444
     *
445
     * @return string Return compiled code segment for the token
446
     */
447 205
    protected static function blockBegin(&$context, $vars) {
448 205
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($vars[1], $context) : array(null, array());
449 205
        if (!$context['flags']['nohbh']) {
450 167
            switch (isset($vars[0][0]) ? $vars[0][0] : null) {
451 167
                case 'if':
452 55
                    $includeZero = (isset($vars['includeZero'][1]) && $vars['includeZero'][1]) ? 'true' : 'false';
453 55
                    return "{$context['ops']['cnd_start']}(" . static::getFuncName($context, 'ifvar', $v[1]) . "\$cx, {$v[0]}, {$includeZero})){$context['ops']['cnd_then']}";
0 ignored issues
show
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...
454 125
                case 'unless':
455 2
                    return "{$context['ops']['cnd_start']}(!" . static::getFuncName($context, 'ifvar', $v[1]) . "\$cx, {$v[0]}, false)){$context['ops']['cnd_then']}";
0 ignored issues
show
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...
456 123
                case 'each':
457 44
                    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...
458 81
                case 'with':
459 15
                    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...
460 15
                        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...
461
                    }
462
            }
463 66
        }
464
465 104
        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...
466
    }
467
468
    /**
469
     * compile {{#foo}} token
470
     *
471
     * @param array<string,array|string|integer> $context current compile context
472
     * @param array<boolean|integer|string|array> $vars parsed arguments list
473
     * @param boolean $isEach the section is #each
474
     *
475
     * @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...
476
     */
477 148
    protected static function section(&$context, $vars, $isEach = false) {
478 148
        if ($isEach) {
479 44
            array_shift($vars);
480 44
            if (!isset($vars[0])) {
481
                $vars[0] = array(null);
482
            }
483 44
        }
484 148
        $v = static::getVariableNameOrSubExpression($vars[0], $context);
485 148
        $each = $isEach ? 'true' : 'false';
486 148
        return $context['ops']['seperator'] . static::getFuncName($context, 'sec', ($isEach ? 'each ' : '') . $v[1]) . "\$cx, {$v[0]}, \$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...
487
    }
488
489
    /**
490
     * compile {{with}} token
491
     *
492
     * @param array<string,array|string|integer> $context current compile context
493
     * @param array<boolean|integer|string|array> $vars parsed arguments list
494
     *
495
     * @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...
496
     */
497 15
    protected static function with(&$context, $vars) {
498 15
        $v = isset($vars[1]) ? static::getVariableNameOrSubExpression($vars[1], $context) : array(null, array());
499 15
        return $context['ops']['seperator'] . static::getFuncName($context, 'wi', 'with ' . $v[1]) . "\$cx, {$v[0]}, \$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...
500
    }
501
502
    /**
503
     * Return compiled PHP code for a handlebars custom helper token
504
     *
505
     * @param array<string,array|string|integer> $context current compile context
506
     * @param array<boolean|integer|string|array> $vars parsed arguments list
507
     * @param boolean $raw is this {{{ token or not
508
     *
509
     * @return string|null Return compiled code segment for the token when the token is custom helper
510
     */
511 389
    protected static function customHelper(&$context, $vars, $raw) {
512 389
        $notHH = !isset($context['hbhelpers'][$vars[0][0]]);
513 389
        if (!isset($context['helpers'][$vars[0][0]]) && $notHH) {
514 292
            return;
515
        }
516
517 107
        $fn = $raw ? 'raw' : $context['ops']['enc'];
518 107
        $ch = array_shift($vars);
519 107
        $v = static::getVariableNames($vars, $context);
520 107
        static::addUsageCount($context, $notHH ? 'helpers' : 'hbhelpers', $ch[0]);
521 107
        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']}";
522
    }
523
524
    /**
525
     * Return compiled PHP code for a handlebars else token
526
     *
527
     * @param array<string,array|string|integer> $context current compile context
528
     *
529
     * @return string Return compiled code segment for the token when the token is else
530
     */
531 44
    protected static function doElse(&$context) {
532 44
        switch ($context['stack'][count($context['stack']) - 2]) {
533 44
            case '[if]':
534 44
            case '[unless]':
535 19
                $context['stack'][] = ':';
536 19
                return "{$context['ops']['cnd_else']}";
537 25
            default:
538 25
                return "{$context['ops']['f_end']}}, function(\$cx, \$in) {{$context['ops']['f_start']}";
539 25
        }
540
    }
541
542
    /**
543
     * Return compiled PHP code for a handlebars lookup token
544
     *
545
     * @param array<string,array|string|integer> $context current compile context
546
     * @param array<boolean|integer|string|array> $vars parsed arguments list
547
     * @param boolean $raw is this {{{ token or not
548
     *
549
     * @return string Return compiled code segment for the token
550
     */
551 2
    protected static function compileLookup(&$context, &$vars, $raw) {
552 2
        $v2 = static::getVariableName($vars[2], $context);
553 2
        $v = static::getVariableName($vars[1], $context, $v2);
554 2
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug']) {
555 2
            return $context['ops']['seperator'] . static::getFuncName($context, $raw ? 'raw' : $context['ops']['enc'], $v[1]) . "\$cx, {$v[0]}){$context['ops']['seperator']}";
556
        } else {
557
            return $raw ? "{$context['ops']['seperator']}$v[0]{$context['ops']['seperator']}" : "{$context['ops']['seperator']}htmlentities((string){$v[0]}, ENT_QUOTES, 'UTF-8'){$context['ops']['seperator']}";
558
        }
559
    }
560
561
    /**
562
     * Return compiled PHP code for a handlebars variable token
563
     *
564
     * @param array<string,array|string|integer> $context current compile context
565
     * @param array<boolean|integer|string|array> $vars parsed arguments list
566
     * @param boolean $raw is this {{{ token or not
567
     *
568
     * @return string Return compiled code segment for the token
569
     */
570 313
    protected static function compileVariable(&$context, &$vars, $raw) {
571 313
        $v = static::getVariableName($vars[0], $context);
572 313
        if ($context['flags']['hbesc'] || $context['flags']['jsobj'] || $context['flags']['jstrue'] || $context['flags']['debug']) {
573 278
            return $context['ops']['seperator'] . static::getFuncName($context, $raw ? 'raw' : $context['ops']['enc'], $v[1]) . "\$cx, {$v[0]}){$context['ops']['seperator']}";
574
        } else {
575 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']}";
576
        }
577
    }
578
579
    /**
580
     * Add usage count to context
581
     *
582
     * @param array<string,array|string|integer> $context current context
583
     * @param string $category ctegory name, can be one of: 'var', 'helpers', 'blockhelpers'
584
     * @param string $name used name
585
     * @param integer $count increment
586
     *
587
     * @expect 1 when input array('usedCount' => array('test' => array())), 'test', 'testname'
588
     * @expect 3 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname'
589
     * @expect 5 when input array('usedCount' => array('test' => array('testname' => 2))), 'test', 'testname', 3
590
     */
591 502
    protected static function addUsageCount(&$context, $category, $name, $count = 1) {
592 502
        if (!isset($context['usedCount'][$category][$name])) {
593 502
            $context['usedCount'][$category][$name] = 0;
594 502
        }
595 502
        return ($context['usedCount'][$category][$name] += $count);
596
    }
597
}
598
599