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

Runtime::p()   C

Complexity

Conditions 9
Paths 10

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 9.0165

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 22
ccs 16
cts 17
cp 0.9412
rs 6.412
cc 9
eloc 14
nc 10
nop 4
crap 9.0165
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, 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 8
    public static function err($cx, $err) {
86 8
        if ($cx['flags']['debug'] & static::DEBUG_ERROR_LOG) {
87 2
            error_log($err);
88 2
            return;
89
        }
90 6
        if ($cx['flags']['debug'] & static::DEBUG_ERROR_EXCEPTION) {
91 3
            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 336
    public static function v($cx, $base, $path) {
120 336
        $count = count($cx['scopes']);
121 336
        while ($base) {
122 307
            $v = $base;
123 307
            foreach ($path as $name) {
124 307
                if (is_array($v) && isset($v[$name])) {
125 302
                    $v = $v[$name];
126 302
                    continue;
127
                }
128 31
                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 29
                if ($cx['flags']['mustlok']) {
139 26
                    unset($v);
140 26
                    break;
141
                }
142 3
                return null;
143 307
            }
144 307
            if (isset($v)) {
145 296
                if ($v instanceof \Closure) {
146 12
                    if ($cx['flags']['mustlam'] || $cx['flags']['lambda']) {
147 12
                        $v = $v();
148 12
                    }
149 12
                }
150 296
                return $v;
151
            }
152 26
            $count--;
153
            switch ($count) {
154 26
                case -1:
155 25
                    $base = $cx['sp_vars']['root'];
156 25
                    break;
157 25
                case -2:
158 24
                    return null;
159 4
                default:
160 4
                    $base = $cx['scopes'][$count];
161 4
            }
162 26
        }
163 33
    }
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 54
    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 54
        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 36
    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 36
        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 272
    public static function raw($cx, $v) {
283 272
        if ($v === true) {
284 1
            if ($cx['flags']['jstrue']) {
285 1
                return 'true';
286
            }
287 1
        }
288
289 272
        if (($v === false)) {
290 6
            if ($cx['flags']['jstrue']) {
291 6
                return 'false';
292
            }
293 1
        }
294
295 267
        if (is_array($v)) {
296 6
            if ($cx['flags']['jsobj']) {
297 6
                if (count(array_diff_key($v, array_keys(array_keys($v)))) > 0) {
298 2
                    return '[object Object]';
299
                } else {
300 5
                    $ret = array();
301 5
                    foreach ($v as $k => $vv) {
302 5
                        $ret[] = static::raw($cx, $vv);
303 5
                    }
304 5
                    return join(',', $ret);
305
                }
306
            } else {
307 1
                return 'Array';
308
            }
309
        }
310
311 267
        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 201
    public static function encq($cx, $var) {
344 201
        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<array|string|integer>|string|integer|null $in input data with current scope
353
     * @param boolean $each true when rendering #each
354
     * @param Closure $cb callback function to render child context
355
     * @param Closure|null $else callback function to render child context when {{else}}
356
     *
357
     * @return string The rendered string of the section
358
     *
359
     * @expect '' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), false, false, false, function () {return 'A';}
360
     * @expect '' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), null, null, false, function () {return 'A';}
361
     * @expect 'A' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), true, true, false, function () {return 'A';}
362
     * @expect 'A' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 0, 0, false, function () {return 'A';}
363
     * @expect '-a=' when input array('scopes' => array(), 'flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array('a'), array('a'), false, function ($c, $i) {return "-$i=";}
364
     * @expect '-a=-b=' when input array('scopes' => array(), 'flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array('a','b'), array('a','b'), false, function ($c, $i) {return "-$i=";}
365
     * @expect '' when input array('scopes' => array(), 'flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 'abc', 'abc', true, function ($c, $i) {return "-$i=";}
366
     * @expect '-b=' when input array('scopes' => array(), 'flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array('a' => 'b'), array('a' => 'b'), true, function ($c, $i) {return "-$i=";}
367
     * @expect '1' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 'b', 'b', false, function ($c, $i) {return count($i);}
368
     * @expect '1' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 1, 1, false, function ($c, $i) {return print_r($i, true);}
369
     * @expect '0' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 0, 0, false, function ($c, $i) {return print_r($i, true);}
370
     * @expect '{"b":"c"}' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array('b' => 'c'), array('b' => 'c'), false, function ($c, $i) {return json_encode($i);}
371
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array(), 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
372
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), array(), 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
373
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), false, 0, true, 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, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
375
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), '', 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
376
     * @expect 'cb' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), '', 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
377
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 0, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
378
     * @expect 'cb' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 0, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
379
     * @expect 'inv' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), new stdClass, 0, true, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
380
     * @expect 'cb' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), new stdClass, 0, false, function ($c, $i) {return 'cb';}, function ($c, $i) {return 'inv';}
381
     * @expect '268' when input array('scopes' => array(), 'flags' => array('spvar' => 1, 'mustlam' => 0, 'lambda' => 0), 'sp_vars'=>array('root' => 0)), array(1,3,4), 0, false, function ($c, $i) {return $i * 2;}
382
     * @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), 0, true, function ($c, $i) {return $i * $c['sp_vars']['index'];}
383
     */
384 151
    public static function sec($cx, $v, $in, $each, $cb, $else = null) {
385 151
        $push = ($in !== $v) || $each;
386
387 151
        if ($v instanceof \Closure) {
388
            if ($cx['flags']['mustlam'] || $cx['flags']['lambda']) {
389
                $v = $v();
390
            }
391
        }
392
393 151
        $isAry = is_array($v) || ($v instanceof \ArrayObject);
394 151
        $isTrav = $v instanceof \Traversable;
395 151
        $loop = $each;
396 151
        $keys = null;
397 151
        $last = null;
398 151
        $isObj = false;
399
400 151
        if ($isAry && $else !== null && count($v) === 0) {
401 3
            $ret = $else($cx, $in);
402 3
            return $ret;
403
        }
404
405
        // #var, detect input type is object or not
406 149
        if (!$loop && $isAry) {
407 63
            $keys = array_keys($v);
408 63
            $loop = (count(array_diff_key($v, array_keys($keys))) == 0);
409 63
            $isObj = !$loop;
410 63
        }
411
412 149
        if ($cx['flags']['mustlam'] && ($v instanceof \Closure)) {
413
            self::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...
414
        }
415
416 149
        if (($loop && $isAry) || $isTrav) {
417 97
            if ($each && !$isTrav) {
418
                // Detect input type is object or not when never done once
419 42
                if ($keys == null) {
420 42
                    $keys = array_keys($v);
421 42
                    $isObj = (count(array_diff_key($v, array_keys($keys))) > 0);
422 42
                }
423 42
            }
424 97
            $ret = array();
425 97
            if ($push) {
426 95
                $cx['scopes'][] = $in;
427 95
            }
428 97
            $i = 0;
429 97
            if ($cx['flags']['spvar']) {
430 86
                $old_spvar = $cx['sp_vars'];
431 86
                $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $cx['sp_vars'], array('_parent' => $old_spvar));
432 86
                if (!$isTrav) {
433 85
                    $last = count($keys) - 1;
434 85
                }
435 86
            }
436
437 97
            $isSparceArray = $isObj && (count(array_filter(array_keys($v), 'is_string')) == 0);
438 97
            foreach ($v as $index => $raw) {
439 91
                if ($cx['flags']['spvar']) {
440 81
                    $cx['sp_vars']['first'] = ($i === 0);
441 81
                    $cx['sp_vars']['last'] = ($i == $last);
442 81
                    $cx['sp_vars']['key'] = $index;
443 81
                    $cx['sp_vars']['index'] = $isSparceArray ? $index : $i;
444 81
                    $i++;
445 81
                }
446 91
                $ret[] = $cb($cx, $raw);
447 96
            }
448 96
            if ($cx['flags']['spvar']) {
449 85
                if ($isObj) {
450 14
                    unset($cx['sp_vars']['key']);
451 14
                } else {
452 73
                    unset($cx['sp_vars']['last']);
453
                }
454 85
                unset($cx['sp_vars']['index']);
455 85
                unset($cx['sp_vars']['first']);
456 85
                $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...
457 85
            }
458 96
            if ($push) {
459 94
                array_pop($cx['scopes']);
460 94
            }
461 96
            return join('', $ret);
462
        }
463 55
        if ($each) {
464 2
            if ($else !== null) {
465 1
                $ret = $else($cx, $v);
466 1
                return $ret;
467
            }
468 2
            return '';
469
        }
470 54
        if ($isAry) {
471 9
            if ($push) {
472 8
                $cx['scopes'][] = $in;
473 8
            }
474 9
            $ret = $cb($cx, $v);
475 9
            if ($push) {
476 8
                array_pop($cx['scopes']);
477 8
            }
478 9
            return $ret;
479
        }
480
481 46
        if ($v === true) {
482 22
            return $cb($cx, $in);
483
        }
484
485 25
        if (($v !== null) && ($v !== false)) {
486 5
            return $cb($cx, $v);
487
        }
488
489 21
        if ($else !== null) {
490 7
            $ret = $else($cx, $in);
491 7
            return $ret;
492
        }
493
494 15
        return '';
495
    }
496
497
    /**
498
     * LightnCandy runtime method for {{#with var}} .
499
     *
500
     * @param array<string,array|string|integer> $cx render time context
501
     * @param array<array|string|integer>|string|integer|null $v value to be the new context
502
     * @param array<array|string|integer>|string|integer|null $in input data with current scope
503
     * @param Closure $cb callback function to render child context
504
     * @param Closure|null $else callback function to render child context when {{else}}
505
     *
506
     * @return string The rendered string of the token
507
     *
508
     * @expect '' when input array(), false, false, function () {return 'A';}
509
     * @expect '' when input array(), null, null, function () {return 'A';}
510
     * @expect '{"a":"b"}' when input array(), array('a'=>'b'), array('a'=>'c'), function ($c, $i) {return json_encode($i);}
511
     * @expect '-b=' when input array(), 'b', array('a'=>'b'), function ($c, $i) {return "-$i=";}
512
     */
513 13
    public static function wi($cx, $v, $in, $cb, $else = null) {
514 13
        if (($v === false) || ($v === null)) {
515 4
            return $else ? $else($cx, $in) : '';
516
        }
517 10
        $cx['scopes'][] = $in;
518 10
        $ret = $cb($cx, $v);
519 10
        array_pop($cx['scopes']);
520 10
        return $ret;
521
    }
522
523
    /**
524
     * LightnCandy runtime method for {{> partial}} .
525
     *
526
     * @param array<string,array|string|integer> $cx render time context
527
     * @param string $p partial name
528
     * @param array<array|string|integer>|string|integer|null $v value to be the new context
529
     *
530
     * @return string The rendered string of the partial
531
     *
532
     */
533 56
    public static function p($cx, $p, $v, $sp = '') {
534 56
        $param = $v[0][0];
535
536 56
        if (is_array($v[1])) {
537 56
            if ($v[0][0] === null) {
538 6
                $param = $v[1];
539 56
            } else if (is_array($v[0][0])) {
540 47
                $param = array_merge($v[0][0], $v[1]);
541 50
            } else if (($cx['flags']['method'] || $cx['flags']['prop']) && is_object($v[0][0])) {
542 1
                foreach ($v[1] as $i => $v) {
543 1
                    $param->$i = $v;
544 1
                }
545 1
            }
546 56
        }
547
548 56
        if (!isset($cx['partials'][$p])) {
549 1
            static::err($cx, "Can not find partial named as '$p' !!");
550
            return '';
551
        }
552
553 55
        return call_user_func($cx['partials'][$p], $cx, $param, $sp);
554
    }
555
556
    /**
557
     * LightnCandy runtime method for custom helpers.
558
     *
559
     * @param array<string,array|string|integer> $cx render time context
560
     * @param string $ch the name of custom helper to be executed
561
     * @param array<array> $vars variables for the helper
562
     * @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
563
     *
564
     * @return string The rendered string of the token
565
     *
566
     * @expect '---' when input array('helpers' => array('a' => function ($i) {return "-$i[0]-";})), 'a', array(array('-'),array()), 'raw'
567
     * @expect '-&amp;-' when input array('helpers' => array('a' => function ($i) {return "-$i[0]-";})), 'a', array(array('&'),array()), 'enc'
568
     * @expect '-&#x27;-' when input array('helpers' => array('a' => function ($i) {return "-$i[0]-";})), 'a', array(array('\''),array()), 'encq'
569
     * @expect '-b-' when input array('helpers' => array('a' => function ($i,$j) {return "-{$j['a']}-";})), 'a', array(array(),array('a' => 'b')), 'raw'
570
     */
571 22
    public static function ch($cx, $ch, $vars, $op) {
572 22
        return static::chret(call_user_func_array($cx['helpers'][$ch], $vars), $op);
573
    }
574
575
    /**
576
     * LightnCandy runtime method to handle response of custom helpers.
577
     *
578
     * @param string|array<string,array|string|integer> $ret return value from custom helper
579
     * @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
580
     *
581
     * @return string The rendered string of the token
582
     *
583
     * @expect '-&-' when input '-&-', 'raw'
584
     * @expect '-&amp;&#039;-' when input '-&\'-', 'enc'
585
     * @expect '-&amp;&#x27;-' when input '-&\'-', 'encq'
586
     * @expect '-&amp;&#039;-' when input array('-&\'-'), 'enc'
587
     * @expect '-&amp;&#x27;-' when input array('-&\'-'), 'encq'
588
     * @expect '-&amp;-' when input array('-&-', false), 'enc'
589
     * @expect '-&-' when input array('-&-', false), 'raw'
590
     * @expect '-&-' when input array('-&-', 'raw'), 'enc'
591
     * @expect '-&amp;&#x27;-' when input array('-&\'-', 'encq'), 'raw'
592
     */
593 144
    public static function chret($ret, $op) {
594 144
        if (is_array($ret)) {
595 8
            if (isset($ret[1]) && $ret[1]) {
596 7
                $op = $ret[1];
597 7
            }
598 8
            $ret = $ret[0];
599 8
        }
600
601
        switch ($op) {
602 144
            case 'enc':
603 9
                return htmlentities($ret, ENT_QUOTES, 'UTF-8');
604 138
            case 'encq':
605 74
                return preg_replace('/=/', '&#x3D;', preg_replace('/`/', '&#x60;', preg_replace('/&#039;/', '&#x27;', htmlentities($ret, ENT_QUOTES, 'UTF-8'))));
606
        }
607 86
        return $ret;
608
    }
609
610
    /**
611
     * LightnCandy runtime method for Handlebars.js style custom helpers.
612
     *
613
     * @param array<string,array|string|integer> $cx render time context
614
     * @param string $ch the name of custom helper to be executed
615
     * @param array<array|string|integer>|string|integer|null $vars variables for the helper
616
     * @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
617
     * @param boolean $inverted the logic will be inverted
618
     * @param Closure|null $cb callback function to render child context
619
     * @param Closure|null $else callback function to render child context when {{else}}
620
     *
621
     * @return string The rendered string of the token
622
     */
623 124
    public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null) {
624 124
        $isBlock = (is_object($cb) && ($cb instanceof \Closure));
625 124
        $args = $vars[0];
626
        $options = array(
627 124
            'name' => $ch,
628 124
            'hash' => $vars[1],
629 124
        );
630
631 124
        if ($isBlock) {
632 49
            $options['_this'] = &$op;
633 49
        } else {
634 81
            $options['_this'] = &$inverted;
635
        }
636
637
        // $invert the logic
638 124
        if ($inverted) {
639 57
            $tmp = $else;
640 57
            $else = $cb;
641 57
            $cb = $tmp;
642 57
        }
643
644 124
        if ($isBlock) {
645
            $options['fn'] = function ($context = '_NO_INPUT_HERE_', $data = null) use ($cx, &$op, $cb, $options) {
646 38
                if ($cx['flags']['echo']) {
647 6
                    ob_start();
648 6
                }
649 38
                if (isset($data['data'])) {
650 6
                    $old_spvar = $cx['sp_vars'];
651 6
                    $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $data['data'], array('_parent' => $old_spvar));
652 6
                }
653 38
                if (($context === '_NO_INPUT_HERE_') || ($context === $op)) {
654 23
                    $ret = $cb($cx, $op);
655 23
                } else {
656 17
                    $cx['scopes'][] = $op;
657 17
                    $ret = $cb($cx, $context);
658 17
                    array_pop($cx['scopes']);
659
                }
660 38
                if (isset($data['data'])) {
661 6
                    $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...
662 6
                }
663 38
                return $cx['flags']['echo'] ? ob_get_clean() : $ret;
664
            };
665 49
        }
666
667 124
        if ($else) {
668 7
            $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...
669 7
                if ($cx['flags']['echo']) {
670 3
                    ob_start();
671 3
                }
672 7
                if ($context === '_NO_INPUT_HERE_') {
673 2
                    $ret = $else($cx, $op);
674 2
                } else {
675 5
                    $cx['scopes'][] = $op;
676 5
                    $ret = $else($cx, $context);
677 5
                    array_pop($cx['scopes']);
678
                }
679 7
                return $cx['flags']['echo'] ? ob_get_clean() : $ret;
680
            };
681 12
        }
682
683 124
        if ($cx['flags']['spvar']) {
684 113
            $options['data'] = $cx['sp_vars'];
685 113
        }
686
687 124
        $args[] = $options;
688 124
        $e = null;
689 124
        $r = true;
690
691
        try {
692 124
            $r = call_user_func_array($cx['hbhelpers'][$ch], $args);
693 124
        } catch (\Exception $E) {
694 2
            $e = "Runtime: call custom helper '$ch' error: " . $E->getMessage();
695
        }
696
697 124
        if($e !== null) {
698 2
            static::err($cx, $e);
699 1
        }
700
701 123
        return static::chret($r, $isBlock ? 'raw' : $op);
702
    }
703
704
    /**
705
     * LightnCandy runtime method for block custom helpers.
706
     *
707
     * @param array<string,array|string|integer> $cx render time context
708
     * @param string $ch the name of custom helper to be executed
709
     * @param array<array|string|integer>|string|integer|null $vars variables for the helper
710
     * @param array<array|string|integer>|string|integer|null $in input data with current scope
711
     * @param boolean $inverted the logic will be inverted
712
     * @param Closure $cb callback function to render child context
713
     * @param Closure|null $else callback function to render child context when {{else}}
714
     *
715
     * @return string The rendered string of the token
716
     *
717
     * @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);}
718
     * @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);}
719
     * @expect '' when input array('blockhelpers' => array('a' => function ($cx,$in) {})), 'a', array('6', 0), 2, false, function($cx, $i) {return implode('.', $i);}
720
     */
721 4
    public static function bch($cx, $ch, $vars, $in, $inverted, $cb, $else = null) {
722 4
        $r = call_user_func($cx['blockhelpers'][$ch], $in, $vars[0], $vars[1]);
723
724
        // $invert the logic
725 4
        if ($inverted) {
726 2
            $tmp = $else;
727 2
            $else = $cb;
728 2
            $cb = $tmp;
729 2
        }
730
731 4
        $ret = '';
732 4
        if ($r === null) {
733 2
            if ($else) {
734 1
                $cx['scopes'][] = $in;
735 1
                $ret = $else($cx, $r);
736 1
                array_pop($cx['scopes']);
737 1
            }
738 2
        } else {
739 3
            if ($cb) {
740 3
                $cx['scopes'][] = $in;
741 3
                $ret = $cb($cx, $r);
742 3
                array_pop($cx['scopes']);
743 3
            }
744
        }
745
746 4
        return $ret;
747
    }
748
}
749
750