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 ( bf7ebd...2818ec )
by Zordius
02:52
created

Compiler::compileToken()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7.01

Importance

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