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 ( 43fc06...9799ea )
by Zordius
02:32
created

Runtime::debug()   F

Complexity

Conditions 16
Paths 1345

Size

Total Lines 32
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 16
Metric Value
dl 0
loc 32
ccs 27
cts 27
cp 1
rs 2.7326
cc 16
eloc 25
nc 1345
nop 3
crap 16

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 to support LightnCandy compiled PHP runtime
16
 *
17
 * @package    LightnCandy
18
 * @author     Zordius <[email protected]>
19
 */
20
21
namespace LightnCandy;
22
23
/**
24
 * LightnCandy class for compiled PHP runtime.
25
 */
26
class Runtime
27
{
28
    const DEBUG_ERROR_LOG = 1;
29
    const DEBUG_ERROR_EXCEPTION = 2;
30
    const DEBUG_TAGS = 4;
31
    const DEBUG_TAGS_ANSI = 12;
32
    const DEBUG_TAGS_HTML = 20;
33
34
    /**
35
     * LightnCandy runtime method for output debug info.
36
     *
37
     * @param string $v expression
38
     * @param string $f runtime function name
39
     * @param array<string,array|string|integer> $cx render time context
40
     *
41
     * @expect '{{123}}' when input '123', 'miss', array('flags' => array('debug' => Runtime::DEBUG_TAGS), 'runtime' => 'LightnCandy\\Runtime'), ''
42
     * @expect '<!--MISSED((-->{{#123}}<!--))--><!--SKIPPED--><!--MISSED((-->{{/123}}<!--))-->' when input '123', 'wi', array('flags' => array('debug' => Runtime::DEBUG_TAGS_HTML), 'runtime' => 'LightnCandy\\Runtime'), false, null, false, function () {return 'A';}
43
     */
44 9
    public static function debug($v, $f, $cx) {
45 9
        $params = array_slice(func_get_args(), 2);
46 9
        $r = call_user_func_array((isset($cx['funcs'][$f]) ? $cx['funcs'][$f] : "{$cx['runtime']}::$f"), $params);
47
48 8
        if ($cx['flags']['debug'] & static::DEBUG_TAGS) {
49 5
            $ansi = $cx['flags']['debug'] & (static::DEBUG_TAGS_ANSI - static::DEBUG_TAGS);
50 5
            $html = $cx['flags']['debug'] & (static::DEBUG_TAGS_HTML - static::DEBUG_TAGS);
51 5
            $cs = ($html ? (($r !== '') ? '<!!--OK((-->' : '<!--MISSED((-->') : '')
52 5
                  . ($ansi ? (($r !== '') ? "\033[0;32m" : "\033[0;31m") : '');
53 5
            $ce = ($html ? '<!--))-->' : '')
54 5
                  . ($ansi ? "\033[0m" : '');
55
            switch ($f) {
56 5
                case 'sec':
57 5
                case 'ifv':
58 5
                case 'unl':
59 5
                case 'wi':
60 3
                    if ($r == '') {
61 3
                        if ($ansi) {
62 1
                            $r = "\033[0;33mSKIPPED\033[0m";
63 1
                        }
64 3
                        if ($html) {
65 2
                            $r = '<!--SKIPPED-->';
66 2
                        }
67 3
                    }
68 3
                    return "$cs{{#{$v}}}$ce{$r}$cs{{/{$v}}}$ce";
69 3
                default:
70 3
                    return "$cs{{{$v}}}$ce";
71 3
            }
72
        } else {
73 3
            return $r;
74
        }
75
    }
76
77
    /**
78
     * LightnCandy runtime method for error
79
     *
80
     * @param array<string,array|string|integer> $cx render time context
81
     * @param string $err error message
82
     *
83
     * @throws \Exception
84
     */
85 7
    public static function err($cx, $err) {
86 7
        if ($cx['flags']['debug'] & static::DEBUG_ERROR_LOG) {
87 2
            error_log($err);
88 2
            return;
89
        }
90 5
        if ($cx['flags']['debug'] & static::DEBUG_ERROR_EXCEPTION) {
91 2
            throw new \Exception($err);
92
        }
93 3
    }
94
95
    /**
96
     * LightnCandy runtime method for missing data error.
97
     *
98
     * @param array<string,array|string|integer> $cx render time context
99
     * @param string $v expression
100
     */
101 5
    public static function miss($cx, $v) {
102 5
        static::err($cx, "Runtime: $v is not exist");
103 4
    }
104
105
    /**
106
     * LightnCandy runtime method for variable lookup. It is slower and only be used for instance property or method detection or lambdas.
107
     *
108
     * @param array<string,array|string|integer> $cx render time context
109
     * @param array<array|string|integer> $base current variable context
110
     * @param array<string|integer> $path array of names for path
111
     *
112
     * @return null|string Return the value or null when not found
113
     *
114
     * @expect null when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0, 'mustlok' => 0)), 0, array('a', 'b')
115
     * @expect 3 when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0), 'mustlok' => 0), array('a' => array('b' => 3)), array('a', 'b')
116
     * @expect null when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0, 'mustlok' => 0)), (Object) array('a' => array('b' => 3)), array('a', 'b')
117
     * @expect 3 when input array('scopes' => array(), 'flags' => array('prop' => 1, 'method' => 0, 'mustlok' => 0)), (Object) array('a' => array('b' => 3)), array('a', 'b')
118
     */
119 100
    public static function v($cx, $base, $path) {
120 100
        $count = count($cx['scopes']);
121 100
        while ($base) {
122 95
            $v = $base;
123 95
            foreach ($path as $name) {
124 95
                if (is_array($v) && isset($v[$name])) {
125 94
                    $v = $v[$name];
126 94
                    continue;
127
                }
128 10
                if (is_object($v)) {
129 5
                    if ($cx['flags']['prop'] && !($v instanceof \Closure) && isset($v->$name)) {
130 3
                        $v = $v->$name;
131 3
                        continue;
132
                    }
133 5
                    if ($cx['flags']['method'] && is_callable(array($v, $name))) {
134 4
                        $v = $v->$name();
135 4
                        continue;
136
                    }
137 3
                }
138 8
                if ($cx['flags']['mustlok']) {
139 5
                    unset($v);
140 5
                    break;
141
                }
142 3
                return null;
143 95
            }
144 95
            if (isset($v)) {
145 91
                if ($v instanceof \Closure) {
146 3
                    if ($cx['flags']['mustlam'] || $cx['flags']['lambda']) {
147 3
                        $v = $v();
148 3
                    }
149 3
                }
150 91
                return $v;
151
            }
152 5
            $count--;
153
            switch ($count) {
154 5
                case -1:
155 4
                    $base = $cx['sp_vars']['root'];
156 4
                    break;
157 5
                case -2:
158 4
                    return null;
159 1
                default:
160 1
                    $base = $cx['scopes'][$count];
161 1
            }
162 5
        }
163 6
    }
164
165
    /**
166
     * LightnCandy runtime method for {{#if var}}.
167
     *
168
     * @param array<string,array|string|integer> $cx render time context
169
     * @param array<array|string|integer>|string|integer|null $v value to be tested
170
     * @param boolean $zero include zero as true
171
     *
172
     * @return boolean Return true when the value is not null nor false.
173
     *
174
     * @expect false when input array(), null, false
175
     * @expect false when input array(), 0, false
176
     * @expect true when input array(), 0, true
177
     * @expect false when input array(), false, false
178
     * @expect true when input array(), true, false
179
     * @expect true when input array(), 1, false
180
     * @expect false when input array(), '', false
181
     * @expect false when input array(), array(), false
182
     * @expect true when input array(), array(''), false
183
     * @expect true when input array(), array(0), false
184
     */
185 13
    public static function ifvar($cx, $v, $zero) {
0 ignored issues
show
Unused Code introduced by
The parameter $cx is not used and could be removed.

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

Loading history...
186 13
        return ($v !== null) && ($v !== false) && ($zero || ($v !== 0) && ($v !== 0.0)) && ($v !== '') && (is_array($v) ? (count($v) > 0) : true);
187
    }
188
189
    /**
190
     * LightnCandy runtime method for {{#if var}} when {{../var}} used.
191
     *
192
     * @param array<string,array|string|integer> $cx render time context
193
     * @param array<array|string|integer>|string|integer|null $v value to be tested
194
     * @param boolean $zero include zero as true
195
     * @param array<array|string|integer> $in input data with current scope
196
     * @param Closure|null $truecb callback function when test result is true
197
     * @param Closure|null $falsecb callback function when test result is false
198
     *
199
     * @return string The rendered string of the section
200
     *
201
     * @expect '' when input array('scopes' => array()), null, false, array(), null
202
     * @expect '' when input array('scopes' => array()), null, false, array(), function () {return 'Y';}
203
     * @expect 'Y' when input array('scopes' => array()), 1, false, array(), function () {return 'Y';}
204
     * @expect 'N' when input array('scopes' => array()), null, false, array(), function () {return 'Y';}, function () {return 'N';}
205
     */
206 1
    public static function ifv($cx, $v, $zero, $in, $truecb, $falsecb = null) {
207 1
        if (static::ifvar($cx, $v, $zero)) {
208 1
            if ($truecb) {
209 1
                return $truecb($cx, $in);
210
            }
211
        } else {
212 1
            if ($falsecb) {
213 1
                return $falsecb($cx, $in);
214
            }
215
        }
216 1
        return '';
217
    }
218
219
    /**
220
     * LightnCandy runtime method for {{#unless var}} when {{../var}} used.
221
     *
222
     * @param array<string,array|string|integer> $cx render time context
223
     * @param array<array|string|integer>|string|integer|null $var value be tested
224
     * @param boolean $zero include zero as true
225
     * @param array<array|string|integer>|string|integer|null $in input data with current scope
226
     * @param Closure $truecb callback function when test result is true
227
     * @param Closure|null $falsecb callback function when test result is false
228
     *
229
     * @return string Return rendered string when the value is not null nor false.
230
     *
231
     * @expect '' when input array('scopes' => array()), null, false, array(), null
232
     * @expect 'Y' when input array('scopes' => array()), null, false, array(), function () {return 'Y';}
233
     * @expect '' when input array('scopes' => array()), 1, false, array(), function () {return 'Y';}
234
     * @expect 'Y' when input array('scopes' => array()), null, false, array(), function () {return 'Y';}, function () {return 'N';}
235
     * @expect 'N' when input array('scopes' => array()), true, false, array(), function () {return 'Y';}, function () {return 'N';}
236
     */
237 1
    public static function unl($cx, $var, $zero, $in, $truecb, $falsecb = null) {
238 1
        return static::ifv($cx, $var, $zero, $in, $falsecb, $truecb);
239
    }
240
241
    /**
242
     * LightnCandy runtime method for {{^var}} inverted section.
243
     *
244
     * @param array<string,array|string|integer> $cx render time context
245
     * @param array<array|string|integer>|string|integer|null $v value to be tested
246
     *
247
     * @return boolean Return true when the value is not null nor false.
248
     *
249
     * @expect true when input array(), null
250
     * @expect false when input array(), 0
251
     * @expect true when input array(), false
252
     * @expect false when input array(), 'false'
253
     * @expect true when input array(), array()
254
     * @expect false when input array(), array('1')
255
     */
256 23
    public static function isec($cx, $v) {
0 ignored issues
show
Unused Code introduced by
The parameter $cx is not used and could be removed.

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

Loading history...
257 23
        return ($v === null) || ($v === false) || (is_array($v) && (count($v) === 0));
258
    }
259
260
    /**
261
     * LightnCandy runtime method for {{{var}}} .
262
     *
263
     * @param array<string,array|string|integer> $cx render time context
264
     * @param array<array|string|integer>|string|integer|null $v value to be output
265
     *
266
     * @return string The raw value of the specified variable
267
     *
268
     * @expect true when input array('flags' => array('jstrue' => 0, 'mustlam' => 0, 'lambda' => 0)), true
269
     * @expect 'true' when input array('flags' => array('jstrue' => 1)), true
270
     * @expect '' when input array('flags' => array('jstrue' => 0, 'mustlam' => 0, 'lambda' => 0)), false
271
     * @expect 'false' when input array('flags' => array('jstrue' => 1)), false
272
     * @expect 'false' when input array('flags' => array('jstrue' => 1)), false, true
273
     * @expect 'Array' when input array('flags' => array('jstrue' => 1, 'jsobj' => 0)), array('a', 'b')
274
     * @expect 'a,b' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1, 'mustlam' => 0, 'lambda' => 0)), array('a', 'b')
275
     * @expect '[object Object]' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('a', 'c' => 'b')
276
     * @expect '[object Object]' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1)), array('c' => 'b')
277
     * @expect 'a,true' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1, 'mustlam' => 0, 'lambda' => 0)), array('a', true)
278
     * @expect 'a,1' when input array('flags' => array('jstrue' => 0, 'jsobj' => 1, 'mustlam' => 0, 'lambda' => 0)), array('a',true)
279
     * @expect 'a,' when input array('flags' => array('jstrue' => 0, 'jsobj' => 1, 'mustlam' => 0, 'lambda' => 0)), array('a',false)
280
     * @expect 'a,false' when input array('flags' => array('jstrue' => 1, 'jsobj' => 1, 'mustlam' => 0, 'lambda' => 0)), array('a',false)
281
     */
282 91
    public static function raw($cx, $v) {
283 91
        if ($v === true) {
284 1
            if ($cx['flags']['jstrue']) {
285 1
                return 'true';
286
            }
287 1
        }
288
289 91
        if (($v === false)) {
290 1
            if ($cx['flags']['jstrue']) {
291 1
                return 'false';
292
            }
293 1
        }
294
295 91
        if (is_array($v)) {
296 5
            if ($cx['flags']['jsobj']) {
297 5
                if (count(array_diff_key($v, array_keys(array_keys($v)))) > 0) {
298 2
                    return '[object Object]';
299
                } else {
300 4
                    $ret = array();
301 4
                    foreach ($v as $k => $vv) {
302 4
                        $ret[] = static::raw($cx, $vv);
303 4
                    }
304 4
                    return join(',', $ret);
305
                }
306
            } else {
307 1
                return 'Array';
308
            }
309
        }
310
311 91
        return "$v";
312
    }
313
314
    /**
315
     * LightnCandy runtime method for {{var}} .
316
     *
317
     * @param array<string,array|string|integer> $cx render time context
318
     * @param array<array|string|integer>|string|integer|null $var value to be htmlencoded
319
     *
320
     * @return string The htmlencoded value of the specified variable
321
     *
322
     * @expect 'a' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a'
323
     * @expect 'a&amp;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a&b'
324
     * @expect 'a&#039;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a\'b'
325
     */
326 44
    public static function enc($cx, $var) {
327 44
        return htmlentities(static::raw($cx, $var), ENT_QUOTES, 'UTF-8');
328
    }
329
330
    /**
331
     * LightnCandy runtime method for {{var}} , and deal with single quote to same as handlebars.js .
332
     *
333
     * @param array<string,array|string|integer> $cx render time context
334
     * @param array<array|string|integer>|string|integer|null $var value to be htmlencoded
335
     *
336
     * @return string The htmlencoded value of the specified variable
337
     *
338
     * @expect 'a' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a'
339
     * @expect 'a&amp;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a&b'
340
     * @expect 'a&#x27;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a\'b'
341
     * @expect '&#x60;a&#x27;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), '`a\'b'
342
     */
343 29
    public static function encq($cx, $var) {
344 29
        return preg_replace('/=/', '&#x3D;', preg_replace('/`/', '&#x60;', preg_replace('/&#039;/', '&#x27;', htmlentities(static::raw($cx, $var), ENT_QUOTES, 'UTF-8'))));
345
    }
346
347
    /**
348
     * LightnCandy runtime method for {{#var}} section.
349
     *
350
     * @param array<string,array|string|integer> $cx render time context
351
     * @param array<array|string|integer>|string|integer|null $v value for the section
352
     * @param array<string>|null $bp block parameters
353
     * @param array<array|string|integer>|string|integer|null $in input data with current scope
354
     * @param boolean $each true when rendering #each
355
     * @param Closure $cb callback function to render child context
356
     * @param Closure|null $else callback function to render child context when {{else}}
357
     *
358
     * @return string The rendered string of the section
359
     *
360
     * @expect '' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), false, null, false, false, function () {return 'A';}
361
     * @expect '' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), null, null, null, false, function () {return 'A';}
362
     * @expect 'A' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), true, null, true, false, function () {return 'A';}
363
     * @expect 'A' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 0, null, 0, false, function () {return 'A';}
364
     * @expect '-a=' when input array('scopes' => array(), 'flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array('a'), null, array('a'), false, function ($c, $i) {return "-$i=";}
365
     * @expect '-a=-b=' when input array('scopes' => array(), 'flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array('a','b'), null, array('a','b'), false, function ($c, $i) {return "-$i=";}
366
     * @expect '' when input array('scopes' => array(), 'flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 'abc', null, 'abc', true, function ($c, $i) {return "-$i=";}
367
     * @expect '-b=' when input array('scopes' => array(), 'flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array('a' => 'b'), null, array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
368
     * @expect '1' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 'b', null, 'b', false, function ($c, $i) {return count($i);}
369
     * @expect '1' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 1, null, 1, false, function ($c, $i) {return print_r($i, true);}
370
     * @expect '0' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 0, null, 0, false, function ($c, $i) {return print_r($i, true);}
371
     * @expect '{"b":"c"}' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array('b' => 'c'), null, array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
372
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array(), null, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
373
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array(), null, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
374
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), false, null, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
375
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), false, null, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
376
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), '', null, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
377
     * @expect 'cb' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), '', null, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
378
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 0, null, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
379
     * @expect 'cb' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 0, null, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
380
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), new stdClass, null, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
381
     * @expect 'cb' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), new stdClass, null, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
382
     * @expect '268' when input array('scopes' => array(), 'flags' => array('spvar' => 1, 'mustlam' => 0, 'lambda' => 0), 'sp_vars'=>array('root' => 0)), array(1,3,4), null, 0, false, function ($c, $i) {return $i * 2;}
383
     * @expect '038' when input array('scopes' => array(), 'flags' => array('spvar' => 1, 'mustlam' => 0, 'lambda' => 0), 'sp_vars'=>array('root' => 0)), array(1,3,'a'=>4), null, 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
384
     */
385 58
    public static function sec($cx, $v, $bp, $in, $each, $cb, $else = null) {
386 58
        $push = ($in !== $v) || $each;
387
388 58
        if ($v instanceof \Closure) {
389
            if ($cx['flags']['mustlam'] || $cx['flags']['lambda']) {
390
                $v = $v();
391
            }
392
        }
393
394 58
        $isAry = is_array($v) || ($v instanceof \ArrayObject);
395 58
        $isTrav = $v instanceof \Traversable;
396 58
        $loop = $each;
397 58
        $keys = null;
398 58
        $last = null;
399 58
        $isObj = false;
400
401 58
        if ($isAry && $else !== null && count($v) === 0) {
402 2
            $ret = $else($cx, $in);
403 2
            return $ret;
404
        }
405
406
        // #var, detect input type is object or not
407 57
        if (!$loop && $isAry) {
408 22
            $keys = array_keys($v);
409 22
            $loop = (count(array_diff_key($v, array_keys($keys))) == 0);
410 22
            $isObj = !$loop;
411 22
        }
412
413 57
        if ($cx['flags']['mustlam'] && ($v instanceof \Closure)) {
414
            static::err('Do not support Section Lambdas!');
0 ignored issues
show
Bug introduced by
The call to err() misses a required argument $err.

This check looks for function calls that miss required arguments.

Loading history...
Documentation introduced by
'Do not support Section Lambdas!' is of type string, but the function expects a array<string,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...
415
        }
416
417 57
        if (($loop && $isAry) || $isTrav) {
418 28
            if ($each && !$isTrav) {
419
                // Detect input type is object or not when never done once
420 12
                if ($keys == null) {
421 12
                    $keys = array_keys($v);
422 12
                    $isObj = (count(array_diff_key($v, array_keys($keys))) > 0);
423 12
                }
424 12
            }
425 28
            $ret = array();
426 28
            if ($push) {
427 28
                $cx['scopes'][] = $in;
428 28
            }
429 28
            $i = 0;
430 28
            if ($cx['flags']['spvar']) {
431 17
                $old_spvar = $cx['sp_vars'];
432 17
                $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $old_spvar, array('_parent' => $old_spvar));
433 17
                if (!$isTrav) {
434 16
                    $last = count($keys) - 1;
435 16
                }
436 17
            }
437
438 28
            $isSparceArray = $isObj && (count(array_filter(array_keys($v), 'is_string')) == 0);
439 28
            foreach ($v as $index => $raw) {
440 27
                if ($cx['flags']['spvar']) {
441 17
                    $cx['sp_vars']['first'] = ($i === 0);
442 17
                    $cx['sp_vars']['last'] = ($i == $last);
443 17
                    $cx['sp_vars']['key'] = $index;
444 17
                    $cx['sp_vars']['index'] = $isSparceArray ? $index : $i;
445 17
                    $i++;
446 17
                }
447 27
                if (isset($bp[0])) {
448
                    $raw = static::m($cx, $raw, array($bp[0] => $raw));
449
                }
450 27
                if (isset($bp[1])) {
451
                    $raw = static::m($cx, $raw, array($bp[1] => $cx['sp_vars']['index']));
452
                }
453 27
                $ret[] = $cb($cx, $raw);
454 28
            }
455 28
            if ($cx['flags']['spvar']) {
456 17
                if ($isObj) {
457 6
                    unset($cx['sp_vars']['key']);
458 6
                } else {
459 13
                    unset($cx['sp_vars']['last']);
460
                }
461 17
                unset($cx['sp_vars']['index']);
462 17
                unset($cx['sp_vars']['first']);
463 17
                $cx['sp_vars'] = $old_spvar;
0 ignored issues
show
Bug introduced by
The variable $old_spvar does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
464 17
            }
465 28
            if ($push) {
466 28
                array_pop($cx['scopes']);
467 28
            }
468 28
            return join('', $ret);
469
        }
470 31
        if ($each) {
471 1
            if ($else !== null) {
472 1
                $ret = $else($cx, $v);
473 1
                return $ret;
474
            }
475 1
            return '';
476
        }
477 31
        if ($isAry) {
478 7
            if ($push) {
479 6
                $cx['scopes'][] = $in;
480 6
            }
481 7
            $ret = $cb($cx, $v);
482 7
            if ($push) {
483 6
                array_pop($cx['scopes']);
484 6
            }
485 7
            return $ret;
486
        }
487
488 25
        if ($v === true) {
489 17
            return $cb($cx, $in);
490
        }
491
492 9
        if (($v !== null) && ($v !== false)) {
493 2
            return $cb($cx, $v);
494
        }
495
496 8
        if ($else !== null) {
497 1
            $ret = $else($cx, $in);
498 1
            return $ret;
499
        }
500
501 8
        return '';
502
    }
503
504
    /**
505
     * LightnCandy runtime method for {{#with var}} .
506
     *
507
     * @param array<string,array|string|integer> $cx render time context
508
     * @param array<array|string|integer>|string|integer|null $v value to be the new context
509
     * @param array<array|string|integer>|string|integer|null $in input data with current scope
510
     * @param array<string>|null $bp block parameters
511
     * @param Closure $cb callback function to render child context
512
     * @param Closure|null $else callback function to render child context when {{else}}
513
     *
514
     * @return string The rendered string of the token
515
     *
516
     * @expect '' when input array(), false, null, false, function () {return 'A';}
517
     * @expect '' when input array(), null, null, null, function () {return 'A';}
518
     * @expect '{"a":"b"}' when input array(), array('a'=>'b'), null, array('a'=>'c'), function ($c, $i) {return json_encode($i);}
519
     * @expect '-b=' when input array(), 'b', null, array('a'=>'b'), function ($c, $i) {return "-$i=";}
520
     */
521 8
    public static function wi($cx, $v, $bp, $in, $cb, $else = null) {
522 8
        if (isset($bp[0])) {
523
            $v = static::m($cx, $v, array($bp[0] => $v));
0 ignored issues
show
Documentation introduced by
array($bp[0] => $v) is of type array<string,array<integ...r>|string|integer|null>, but the function expects a array<integer,array|stri...er>|string|integer|null.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
524
        }
525 8
        if (($v === false) || ($v === null)) {
526 3
            return $else ? $else($cx, $in) : '';
527
        }
528 6
        $cx['scopes'][] = $in;
529 6
        $ret = $cb($cx, $v);
530 6
        array_pop($cx['scopes']);
531 6
        return $ret;
532
    }
533
534
    /**
535
     * LightnCandy runtime method to get merged context
536
     *
537
     * @param array<string,array|string|integer> $cx render time context
538
     * @param array<array|string|integer>|string|integer|null $a the context to be merged
539
     * @param array<array|string|integer>|string|integer|null $b the new context to overwrite
540
     *
541
     * @return array<array|string|integer>|string|integer the merged context object
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string|integer|null? Also, consider making the array more specific, something like array<String>, or String[].

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

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
542
     *
543
     */
544 24
    public static function m($cx, $a, $b) {
545 24
        if (is_array($b)) {
546 24
            if ($a === null) {
547 3
                return $b;
548 21
            } else if (is_array($a)) {
549 19
                return array_merge($a, $b);
550 2
            } else if (($cx['flags']['method'] || $cx['flags']['prop']) && is_object($a)) {
551 1
                foreach ($b as $i => $v) {
552 1
                    $a->$i = $v;
553 1
                }
554 1
            }
555 2
        }
556 2
        return $a;
557
    }
558
559
    /**
560
     * LightnCandy runtime method for {{> partial}} .
561
     *
562
     * @param array<string,array|string|integer> $cx render time context
563
     * @param string $p partial name
564
     * @param array<array|string|integer>|string|integer|null $v value to be the new context
565
     *
566
     * @return string The rendered string of the partial
567
     *
568
     */
569 24
    public static function p($cx, $p, $v, $sp = '') {
570 24
        if (!isset($cx['partials'][$p])) {
571
            static::err($cx, "Can not find partial named as '$p' !!");
572
            return '';
573
        }
574
575 24
        return call_user_func($cx['partials'][$p], $cx, static::m($cx, $v[0][0], $v[1]), $sp);
576
    }
577
578
    /**
579
     * LightnCandy runtime method for custom helpers.
580
     *
581
     * @param array<string,array|string|integer> $cx render time context
582
     * @param string $ch the name of custom helper to be executed
583
     * @param array<array> $vars variables for the helper
584
     * @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
585
     *
586
     * @return string The rendered string of the token
587
     *
588
     * @expect '---' when input array('helpers' => array('a' => function ($i) {return "-$i[0]-";})), 'a', array(array('-'),array()), 'raw'
589
     * @expect '-&amp;-' when input array('helpers' => array('a' => function ($i) {return "-$i[0]-";})), 'a', array(array('&'),array()), 'enc'
590
     * @expect '-&#x27;-' when input array('helpers' => array('a' => function ($i) {return "-$i[0]-";})), 'a', array(array('\''),array()), 'encq'
591
     * @expect '-b-' when input array('helpers' => array('a' => function ($i,$j) {return "-{$j['a']}-";})), 'a', array(array(),array('a' => 'b')), 'raw'
592
     */
593 22
    public static function ch($cx, $ch, $vars, $op) {
594 22
        return static::chret(call_user_func_array($cx['helpers'][$ch], $vars), $op);
595
    }
596
597
    /**
598
     * LightnCandy runtime method to handle response of custom helpers.
599
     *
600
     * @param string|array<string,array|string|integer> $ret return value from custom helper
601
     * @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
602
     *
603
     * @return string The rendered string of the token
604
     *
605
     * @expect '-&-' when input '-&-', 'raw'
606
     * @expect '-&amp;&#039;-' when input '-&\'-', 'enc'
607
     * @expect '-&amp;&#x27;-' when input '-&\'-', 'encq'
608
     * @expect '-&amp;&#039;-' when input array('-&\'-'), 'enc'
609
     * @expect '-&amp;&#x27;-' when input array('-&\'-'), 'encq'
610
     * @expect '-&amp;-' when input array('-&-', false), 'enc'
611
     * @expect '-&-' when input array('-&-', false), 'raw'
612
     * @expect '-&-' when input array('-&-', 'raw'), 'enc'
613
     * @expect '-&amp;&#x27;-' when input array('-&\'-', 'encq'), 'raw'
614
     */
615 57
    public static function chret($ret, $op) {
616 57
        if (is_array($ret)) {
617 7
            if (isset($ret[1]) && $ret[1]) {
618 6
                $op = $ret[1];
619 6
            }
620 7
            $ret = $ret[0];
621 7
        }
622
623
        switch ($op) {
624 57
            case 'enc':
625 9
                return htmlentities($ret, ENT_QUOTES, 'UTF-8');
626 51
            case 'encq':
627 23
                return preg_replace('/=/', '&#x3D;', preg_replace('/`/', '&#x60;', preg_replace('/&#039;/', '&#x27;', htmlentities($ret, ENT_QUOTES, 'UTF-8'))));
628
        }
629 33
        return $ret;
630
    }
631
632
    /**
633
     * LightnCandy runtime method for Handlebars.js style custom helpers.
634
     *
635
     * @param array<string,array|string|integer> $cx render time context
636
     * @param string $ch the name of custom helper to be executed
637
     * @param array<array|string|integer>|string|integer|null $vars variables for the helper
638
     * @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
639
     * @param boolean $inverted the logic will be inverted
640
     * @param Closure|null $cb callback function to render child context
641
     * @param Closure|null $else callback function to render child context when {{else}}
642
     *
643
     * @return string The rendered string of the token
644
     */
645 37
    public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null) {
646 37
        $isBlock = (is_object($cb) && ($cb instanceof \Closure));
647 37
        $args = $vars[0];
648
        $options = array(
649 37
            'name' => $ch,
650 37
            'hash' => $vars[1],
651 37
            'fn.blockParams' => 0,
652 37
        );
653
654 37
        if ($isBlock) {
655 14
            $options['_this'] = &$op;
656 14
        } else {
657 23
            $options['_this'] = &$inverted;
658
        }
659
660 37
        if (isset($vars[2])) {
661
            $options['fn.blockParams'] = count($vars[2]);
662
        }
663
664
        // $invert the logic
665 37
        if ($inverted) {
666 20
            $tmp = $else;
667 20
            $else = $cb;
668 20
            $cb = $tmp;
669 20
        }
670
671 37
        if ($isBlock) {
672
            $options['fn'] = function ($context = '_NO_INPUT_HERE_', $data = null) use ($cx, &$op, $cb, $options, $vars) {
673 9
                if ($cx['flags']['echo']) {
674 6
                    ob_start();
675 6
                }
676 9
                if (isset($data['data'])) {
677 1
                    $old_spvar = $cx['sp_vars'];
678 1
                    $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $data['data'], array('_parent' => $old_spvar));
679 1
                }
680 9
                $ex = false;
681 9
                if (isset($data['blockParams']) && isset($vars[2])) {
682
                    $ex = array_combine($vars[2], array_slice($data['blockParams'], 0, count($vars[2])));
683
                    array_unshift($cx['blparam'], $ex);
684 9
                } else if (isset($cx['blparam'][0])) {
685
                    $ex = $cx['blparam'][0];
686
                }
687 9
                if (($context === '_NO_INPUT_HERE_') || ($context === $op)) {
688 4
                    $ret = $cb($cx, is_array($ex) ? static::m($cx, $op, $ex) : $op);
689 4
                } else {
690 6
                    $cx['scopes'][] = $op;
691 6
                    $ret = $cb($cx, is_array($ex) ? static::m($cx, $context, $ex) : $context);
692 6
                    array_pop($cx['scopes']);
693
                }
694 9
                if (isset($data['data'])) {
695 1
                    $cx['sp_vars'] = $old_spvar;
0 ignored issues
show
Bug introduced by
The variable $old_spvar does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
696 1
                }
697 9
                return $cx['flags']['echo'] ? ob_get_clean() : $ret;
698
            };
699 14
        }
700
701 37
        if ($else) {
702 3
            $options['inverse'] = function ($context = '_NO_INPUT_HERE_', $data = null) use ($cx, $op, $else) {
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

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

Loading history...
703 3
                if ($cx['flags']['echo']) {
704 3
                    ob_start();
705 3
                }
706 3
                if ($context === '_NO_INPUT_HERE_') {
707 2
                    $ret = $else($cx, $op);
708 2
                } else {
709 1
                    $cx['scopes'][] = $op;
710 1
                    $ret = $else($cx, $context);
711 1
                    array_pop($cx['scopes']);
712
                }
713 3
                return $cx['flags']['echo'] ? ob_get_clean() : $ret;
714
            };
715 7
        }
716
717 37
        if ($cx['flags']['spvar']) {
718 26
            $options['data'] = $cx['sp_vars'];
719 26
        }
720
721 37
        $args[] = $options;
722 37
        $e = null;
723 37
        $r = true;
724
725
        try {
726 37
            $r = call_user_func_array($cx['hbhelpers'][$ch], $args);
727 37
        } catch (\Exception $E) {
728 2
            $e = "Runtime: call custom helper '$ch' error: " . $E->getMessage();
729
        }
730
731 37
        if($e !== null) {
732 2
            static::err($cx, $e);
733 1
        }
734
735 36
        return static::chret($r, $isBlock ? 'raw' : $op);
736
    }
737
738
    /**
739
     * LightnCandy runtime method for block custom helpers.
740
     *
741
     * @param array<string,array|string|integer> $cx render time context
742
     * @param string $ch the name of custom helper to be executed
743
     * @param array<array|string|integer>|string|integer|null $vars variables for the helper
744
     * @param array<array|string|integer>|string|integer|null $in input data with current scope
745
     * @param boolean $inverted the logic will be inverted
746
     * @param Closure $cb callback function to render child context
747
     * @param Closure|null $else callback function to render child context when {{else}}
748
     *
749
     * @return string The rendered string of the token
750
     *
751
     * @expect '4.2.3' when input array('blockhelpers' => array('a' => function ($cx) {return array($cx,2,3);})), 'a', array(0, 0), 4, false, function($cx, $i) {return implode('.', $i);}
752
     * @expect '2.6.5' when input array('blockhelpers' => array('a' => function ($cx,$in) {return array($cx,$in[0],5);})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
753
     * @expect '' when input array('blockhelpers' => array('a' => function ($cx,$in) {})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
754
     */
755 4
    public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = null) {
756 4
        $r = call_user_func($cx['blockhelpers'][$ch], $in, $vars[0], $vars[1]);
757
758
        // $invert the logic
759 4
        if ($inverted) {
760 2
            $tmp = $else;
761 2
            $else = $cb;
762 2
            $cb = $tmp;
763 2
        }
764
765 4
        $ret = '';
766 4
        if ($r === null) {
767 2
            if ($else) {
768 1
                $cx['scopes'][] = $in;
769 1
                $ret = $else($cx, $r);
770 1
                array_pop($cx['scopes']);
771 1
            }
772 2
        } else {
773 3
            if ($cb) {
774 3
                $cx['scopes'][] = $in;
775 3
                $ret = $cb($cx, $r);
776 3
                array_pop($cx['scopes']);
777 3
            }
778
        }
779
780 4
        return $ret;
781
    }
782
}
783
784