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 — master ( 3164c8...e80f38 )
by Zordius
02:30
created

Runtime::exch()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 11
cts 11
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 12
nc 4
nop 4
crap 3
1
<?php
2
/*
3
4
Copyrights for code authored by Yahoo! Inc. is licensed under the following terms:
5
MIT License
6
Copyright (c) 2013-2016 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
use \LightnCandy\Encoder;
23
24
/**
25
 * LightnCandy class for compiled PHP runtime.
26
 */
27
class Runtime extends Encoder
28
{
29
    const DEBUG_ERROR_LOG = 1;
30
    const DEBUG_ERROR_EXCEPTION = 2;
31
    const DEBUG_TAGS = 4;
32
    const DEBUG_TAGS_ANSI = 12;
33
    const DEBUG_TAGS_HTML = 20;
34
35
    /**
36
     * Output debug info.
37
     *
38
     * @param string $v expression
39
     * @param string $f runtime function name
40
     * @param array<string,array|string|integer> $cx render time context for lightncandy
41
     *
42
     * @expect '{{123}}' when input '123', 'miss', array('flags' => array('debug' => Runtime::DEBUG_TAGS), 'runtime' => 'LightnCandy\\Runtime'), ''
43
     * @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';}
44
     */
45 9
    public static function debug($v, $f, $cx) {
46
        // Build array of reference for call_user_func_array
47 9
        $P = func_get_args();
48 9
        $params = array();
49 9
        for ($i=2;$i<count($P);$i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
50 9
            $params[] = &$P[$i];
51
        }
52 9
        $r = call_user_func_array((isset($cx['funcs'][$f]) ? $cx['funcs'][$f] : "{$cx['runtime']}::$f"), $params);
53
54 8
        if ($cx['flags']['debug'] & static::DEBUG_TAGS) {
55 5
            $ansi = $cx['flags']['debug'] & (static::DEBUG_TAGS_ANSI - static::DEBUG_TAGS);
56 5
            $html = $cx['flags']['debug'] & (static::DEBUG_TAGS_HTML - static::DEBUG_TAGS);
57 5
            $cs = ($html ? (($r !== '') ? '<!!--OK((-->' : '<!--MISSED((-->') : '')
58 5
                  . ($ansi ? (($r !== '') ? "\033[0;32m" : "\033[0;31m") : '');
59 5
            $ce = ($html ? '<!--))-->' : '')
60 5
                  . ($ansi ? "\033[0m" : '');
61
            switch ($f) {
62 5
                case 'sec':
63 3
                case 'wi':
64 3
                    if ($r == '') {
65 3
                        if ($ansi) {
66 1
                            $r = "\033[0;33mSKIPPED\033[0m";
67
                        }
68 3
                        if ($html) {
69 2
                            $r = '<!--SKIPPED-->';
70
                        }
71
                    }
72 3
                    return "$cs{{#{$v}}}$ce{$r}$cs{{/{$v}}}$ce";
73
                default:
74 3
                    return "$cs{{{$v}}}$ce";
75
            }
76
        } else {
77 3
            return $r;
78
        }
79
    }
80
81
    /**
82
     * Handle error by error_log or throw exception.
83
     *
84
     * @param array<string,array|string|integer> $cx render time context for lightncandy
85
     * @param string $err error message
86
     *
87
     * @throws \Exception
88
     */
89 12
    public static function err($cx, $err) {
90 12
        if ($cx['flags']['debug'] & static::DEBUG_ERROR_LOG) {
91 2
            error_log($err);
92 2
            return;
93
        }
94 10
        if ($cx['flags']['debug'] & static::DEBUG_ERROR_EXCEPTION) {
95 6
            throw new \Exception($err);
96
        }
97 4
    }
98
99
    /**
100
     * Handle missing data error.
101
     *
102
     * @param array<string,array|string|integer> $cx render time context for lightncandy
103
     * @param string $v expression
104
     */
105 5
    public static function miss($cx, $v) {
106 5
        static::err($cx, "Runtime: $v does not exist");
107 4
    }
108
109
    /**
110
     * For {{log}} .
111
     *
112
     * @param array<string,array|string|integer> $cx render time context for lightncandy
113
     * @param string $v expression
114
     */
115
    public static function lo($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...
116
        error_log(var_export($v[0], true));
117
        return '';
118
    }
119
120
    /**
121
     * Resursive lookup variable and helpers. This is slow and will only be used for instance property or method detection or lambdas.
122
     *
123
     * @param array<string,array|string|integer> $cx render time context for lightncandy
124
     * @param array|string|boolean|integer|double|null $in current context
125
     * @param array<array|string|integer> $base current variable context
126
     * @param array<string|integer> $path array of names for path
127
     * @param array|null $args extra arguments for lambda
128
     *
129
     * @return null|string Return the value or null when not found
130
     *
131
     * @expect null when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0, 'mustlok' => 0)), null, 0, array('a', 'b')
132
     * @expect 3 when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0), 'mustlok' => 0), null, array('a' => array('b' => 3)), array('a', 'b')
133
     * @expect null when input array('scopes' => array(), 'flags' => array('prop' => 0, 'method' => 0, 'mustlok' => 0)), null, (Object) array('a' => array('b' => 3)), array('a', 'b')
134
     * @expect 3 when input array('scopes' => array(), 'flags' => array('prop' => 1, 'method' => 0, 'mustlok' => 0)), null, (Object) array('a' => array('b' => 3)), array('a', 'b')
135
     */
136 386
    public static function v($cx, $in, $base, $path, $args = null) {
137 386
        $count = count($cx['scopes']);
138 386
        $plen = count($path);
139 386
        while ($base) {
140 350
            $v = $base;
141 350
            foreach ($path as $i => $name) {
142 350
                if (is_array($v)) {
143 349
                    if (isset($v[$name])) {
144 345
                        $v = $v[$name];
145 345
                        continue;
146
                    }
147 31
                    if (($i === $plen - 1) && ($name === 'length')) {
148 1
                        return count($v);
149
                    }
150
                }
151 36
                if (is_object($v)) {
152 5
                    if ($cx['flags']['prop'] && !($v instanceof \Closure) && isset($v->$name)) {
153 3
                        $v = $v->$name;
154 3
                        continue;
155
                    }
156 5
                    if ($cx['flags']['method'] && is_callable(array($v, $name))) {
157 4
                        $v = $v->$name();
158 4
                        continue;
159
                    }
160
                }
161 34
                if ($cx['flags']['mustlok']) {
162 31
                    unset($v);
163 31
                    break;
164
                }
165 3
                return null;
166
            }
167 349
            if (isset($v)) {
168 338
                if ($v instanceof \Closure) {
169 29
                    if ($cx['flags']['mustlam'] || $cx['flags']['lambda']) {
170 29
                        if (!$cx['flags']['knohlp'] && ($args || ($args === 0))) {
171 20
                            $A = $args ? $args[0] : array();
172 20
                            $A[] = array('hash' => $args[1], '_this' => $in);
173
                        } else {
174 10
                            $A = array($in);
175
                        }
176 29
                        $v = call_user_func_array($v, $A);
177
                    }
178
                }
179 338
                return $v;
180
            }
181 31
            $count--;
182
            switch ($count) {
183 31
                case -1:
184 30
                    $base = $cx['sp_vars']['root'];
185 30
                    break;
186 30
                case -2:
187 29
                    return null;
188
                default:
189 6
                    $base = $cx['scopes'][$count];
190
            }
191
        }
192 40
        if ($args) {
193 3
            static::err($cx, 'Can not find helper or lambda: "' . implode('.', $path) . '" !');
194
        }
195 40
    }
196
197
    /**
198
     * For {{#if}} .
199
     *
200
     * @param array<string,array|string|integer> $cx render time context for lightncandy
201
     * @param array<array|string|integer>|string|integer|null $v value to be tested
202
     * @param boolean $zero include zero as true
203
     *
204
     * @return boolean Return true when the value is not null nor false.
205
     *
206
     * @expect false when input array(), null, false
207
     * @expect false when input array(), 0, false
208
     * @expect true when input array(), 0, true
209
     * @expect false when input array(), false, false
210
     * @expect true when input array(), true, false
211
     * @expect true when input array(), 1, false
212
     * @expect false when input array(), '', false
213
     * @expect false when input array(), array(), false
214
     * @expect true when input array(), array(''), false
215
     * @expect true when input array(), array(0), false
216
     */
217 74
    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...
218 74
        return ($v !== null) && ($v !== false) && ($zero || ($v !== 0) && ($v !== 0.0)) && ($v !== '') && (is_array($v) ? (count($v) > 0) : true);
219
    }
220
221
    /**
222
     * For {{^var}} .
223
     *
224
     * @param array<string,array|string|integer> $cx render time context for lightncandy
225
     * @param array<array|string|integer>|string|integer|null $v value to be tested
226
     *
227
     * @return boolean Return true when the value is not null nor false.
228
     *
229
     * @expect true when input array(), null
230
     * @expect false when input array(), 0
231
     * @expect true when input array(), false
232
     * @expect false when input array(), 'false'
233
     * @expect true when input array(), array()
234
     * @expect false when input array(), array('1')
235
     */
236 37
    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...
237 37
        return ($v === null) || ($v === false) || (is_array($v) && (count($v) === 0));
238
    }
239
240
    /**
241
     * For {{var}} .
242
     *
243
     * @param array<string,array|string|integer> $cx render time context for lightncandy
244
     * @param array<array|string|integer>|string|integer|null $var value to be htmlencoded
245
     *
246
     * @return string The htmlencoded value of the specified variable
247
     *
248
     * @expect 'a' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a'
249
     * @expect 'a&amp;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a&b'
250
     * @expect 'a&#039;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a\'b'
251
     * @expect 'a&b' when input null, new \LightnCandy\SafeString('a&b')
252
     */
253 45
    public static function enc($cx, $var) {
254 45
        if ($var instanceof \LightnCandy\SafeString) {
255 1
            return (string)$var;
256
        }
257
258 45
        return htmlspecialchars(static::raw($cx, $var), ENT_QUOTES, 'UTF-8');
259
    }
260
261
    /**
262
     * For {{var}} , do html encode just like handlebars.js .
263
     *
264
     * @param array<string,array|string|integer> $cx render time context for lightncandy
265
     * @param array<array|string|integer>|string|integer|null $var value to be htmlencoded
266
     *
267
     * @return string The htmlencoded value of the specified variable
268
     *
269
     * @expect 'a' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a'
270
     * @expect 'a&amp;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a&b'
271
     * @expect 'a&#x27;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), 'a\'b'
272
     * @expect '&#x60;a&#x27;b' when input array('flags' => array('mustlam' => 0, 'lambda' => 0)), '`a\'b'
273
     */
274 334
    public static function encq($cx, $var) {
275 334
        if ($var instanceof \LightnCandy\SafeString) {
276 3
            return (string)$var;
277
        }
278
279 331
        return str_replace(array('=', '`', '&#039;'), array('&#x3D;', '&#x60;', '&#x27;'), htmlspecialchars(static::raw($cx, $var), ENT_QUOTES, 'UTF-8'));
280
    }
281
282
    /**
283
     * For {{#var}} or {{#each}} .
284
     *
285
     * @param array<string,array|string|integer> $cx render time context for lightncandy
286
     * @param array<array|string|integer>|string|integer|null $v value for the section
287
     * @param array<string>|null $bp block parameters
288
     * @param array<array|string|integer>|string|integer|null $in input data with current scope
289
     * @param boolean $each true when rendering #each
290
     * @param Closure $cb callback function to render child context
291
     * @param Closure|null $else callback function to render child context when {{else}}
292
     *
293
     * @return string The rendered string of the section
294
     *
295
     * @expect '' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), false, null, false, false, function () {return 'A';}
296
     * @expect '' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), null, null, null, false, function () {return 'A';}
297
     * @expect 'A' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), true, null, true, false, function () {return 'A';}
298
     * @expect 'A' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 0, null, 0, false, function () {return 'A';}
299
     * @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=";}
300
     * @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=";}
301
     * @expect '' when input array('scopes' => array(), 'flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 'abc', null, 'abc', true, function ($c, $i) {return "-$i=";}
302
     * @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=";}
303
     * @expect '1' when input array('flags' => array('spvar' => 0, 'mustlam' => 0, 'lambda' => 0)), 'b', null, 'b', false, function ($c, $i) {return count($i);}
304
     * @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);}
305
     * @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);}
306
     * @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);}
307
     * @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';}
308
     * @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';}
309
     * @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';}
310
     * @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';}
311
     * @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';}
312
     * @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';}
313
     * @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';}
314
     * @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';}
315
     * @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';}
316
     * @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';}
317
     * @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;}
318
     * @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'];}
319
     */
320 163
    public static function sec($cx, $v, $bp, $in, $each, $cb, $else = null) {
321 163
        $push = ($in !== $v) || $each;
322
323 163
        $isAry = is_array($v) || ($v instanceof \ArrayObject);
324 163
        $isTrav = $v instanceof \Traversable;
325 163
        $loop = $each;
326 163
        $keys = null;
327 163
        $last = null;
328 163
        $isObj = false;
329
330 163
        if ($isAry && $else !== null && count($v) === 0) {
331 3
            $ret = $else($cx, $in);
332 3
            return $ret;
333
        }
334
335
        // #var, detect input type is object or not
336 161
        if (!$loop && $isAry) {
337 64
            $keys = array_keys($v);
338 64
            $loop = (count(array_diff_key($v, array_keys($keys))) == 0);
339 64
            $isObj = !$loop;
340
        }
341
342 161
        if (($loop && $isAry) || $isTrav) {
343 102
            if ($each && !$isTrav) {
344
                // Detect input type is object or not when never done once
345 48
                if ($keys == null) {
346 48
                    $keys = array_keys($v);
347 48
                    $isObj = (count(array_diff_key($v, array_keys($keys))) > 0);
348
                }
349
            }
350 102
            $ret = array();
351 102
            if ($push) {
352 100
                $cx['scopes'][] = $in;
353
            }
354 102
            $i = 0;
355 102
            if ($cx['flags']['spvar']) {
356 92
                $old_spvar = $cx['sp_vars'];
357 92
                $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $old_spvar, array('_parent' => $old_spvar));
358 92
                if (!$isTrav) {
359 91
                    $last = count($keys) - 1;
360
                }
361
            }
362
363 102
            $isSparceArray = $isObj && (count(array_filter(array_keys($v), 'is_string')) == 0);
364 102
            foreach ($v as $index => $raw) {
365 95
                if ($cx['flags']['spvar']) {
366 86
                    $cx['sp_vars']['first'] = ($i === 0);
367 86
                    $cx['sp_vars']['last'] = ($i == $last);
368 86
                    $cx['sp_vars']['key'] = $index;
369 86
                    $cx['sp_vars']['index'] = $isSparceArray ? $index : $i;
370 86
                    $i++;
371
                }
372 95
                if (isset($bp[0])) {
373 2
                    $raw = static::m($cx, $raw, array($bp[0] => $raw));
374
                }
375 95
                if (isset($bp[1])) {
376 1
                    $raw = static::m($cx, $raw, array($bp[1] => $cx['sp_vars']['index']));
377
                }
378 95
                $ret[] = $cb($cx, $raw);
379
            }
380 101
            if ($cx['flags']['spvar']) {
381 91
                if ($isObj) {
382 14
                    unset($cx['sp_vars']['key']);
383
                } else {
384 79
                    unset($cx['sp_vars']['last']);
385
                }
386 91
                unset($cx['sp_vars']['index']);
387 91
                unset($cx['sp_vars']['first']);
388 91
                $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...
389
            }
390 101
            if ($push) {
391 99
                array_pop($cx['scopes']);
392
            }
393 101
            return join('', $ret);
394
        }
395 61
        if ($each) {
396 2
            if ($else !== null) {
397 1
                $ret = $else($cx, $v);
398 1
                return $ret;
399
            }
400 2
            return '';
401
        }
402 60
        if ($isAry) {
403 11
            if ($push) {
404 10
                $cx['scopes'][] = $in;
405
            }
406 11
            $ret = $cb($cx, $v);
407 11
            if ($push) {
408 10
                array_pop($cx['scopes']);
409
            }
410 11
            return $ret;
411
        }
412
413 50
        if ($v === true) {
414 22
            return $cb($cx, $in);
415
        }
416
417 29
        if (($v !== null) && ($v !== false)) {
418 6
            return $cb($cx, $v);
419
        }
420
421 24
        if ($else !== null) {
422 10
            $ret = $else($cx, $in);
423 10
            return $ret;
424
        }
425
426 15
        return '';
427
    }
428
429
    /**
430
     * For {{#with}} .
431
     *
432
     * @param array<string,array|string|integer> $cx render time context for lightncandy
433
     * @param array<array|string|integer>|string|integer|null $v value to be the new context
434
     * @param array<array|string|integer>|string|integer|null $in input data with current scope
435
     * @param array<string>|null $bp block parameters
436
     * @param Closure $cb callback function to render child context
437
     * @param Closure|null $else callback function to render child context when {{else}}
438
     *
439
     * @return string The rendered string of the token
440
     *
441
     * @expect '' when input array(), false, null, false, function () {return 'A';}
442
     * @expect '' when input array(), null, null, null, function () {return 'A';}
443
     * @expect '{"a":"b"}' when input array(), array('a'=>'b'), null, array('a'=>'c'), function ($c, $i) {return json_encode($i);}
444
     * @expect '-b=' when input array(), 'b', null, array('a'=>'b'), function ($c, $i) {return "-$i=";}
445
     */
446 28
    public static function wi($cx, $v, $bp, $in, $cb, $else = null) {
447 28
        if (isset($bp[0])) {
448 4
            $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...
449
        }
450 28
        if (($v === false) || ($v === null) || (is_array($v) && (count($v) === 0))) {
451 5
            return $else ? $else($cx, $in) : '';
452
        }
453 24
        if ($v === $in) {
454 5
            $ret = $cb($cx, $v);
455
        } else {
456 19
            $cx['scopes'][] = $in;
457 19
            $ret = $cb($cx, $v);
458 19
            array_pop($cx['scopes']);
459
        }
460 24
        return $ret;
461
    }
462
463
    /**
464
     * Get merged context.
465
     *
466
     * @param array<string,array|string|integer> $cx render time context for lightncandy
467
     * @param array<array|string|integer>|string|integer|null $a the context to be merged
468
     * @param array<array|string|integer>|string|integer|null $b the new context to overwrite
469
     *
470
     * @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...
471
     *
472
     */
473 93
    public static function m($cx, $a, $b) {
474 93
        if (is_array($b)) {
475 93
            if ($a === null) {
476 8
                return $b;
477 86
            } else if (is_array($a)) {
478 77
                return array_merge($a, $b);
479 9
            } else if (($cx['flags']['method'] || $cx['flags']['prop']) && is_object($a)) {
480 4
                foreach ($b as $i => $v) {
481 1
                    $a->$i = $v;
482
                }
483
            }
484
        }
485 9
        return $a;
486
    }
487
488
    /**
489
     * For {{> partial}} .
490
     *
491
     * @param array<string,array|string|integer> $cx render time context for lightncandy
492
     * @param string $p partial name
493
     * @param array<array|string|integer>|string|integer|null $v value to be the new context
494
     *
495
     * @return string The rendered string of the partial
496
     *
497
     */
498 88
    public static function p($cx, $p, $v, $pid, $sp = '') {
499 88
        $pp = ($p === '@partial-block') ? "$p" . ($pid > 0 ? $pid : $cx['partialid']) : $p;
500
501 88
        if (!isset($cx['partials'][$pp])) {
502 2
            static::err($cx, "Can not find partial named as '$pp' !!");
503 1
            return '';
504
        }
505
506 86
        $cx['partialid'] = ($p === '@partial-block') ? (($pid > 0) ? $pid : (($cx['partialid'] > 0) ? $cx['partialid'] - 1 : 0)) : $pid;
507
508 86
        return call_user_func($cx['partials'][$pp], $cx, static::m($cx, $v[0][0], $v[1]), $sp);
509
    }
510
511
    /**
512
     * For {{#* inlinepartial}} .
513
     *
514
     * @param array<string,array|string|integer> $cx render time context for lightncandy
515
     * @param string $p partial name
516
     * @param Closure $code the compiled partial code
517
     *
518
     */
519 7
    public static function in(&$cx, $p, $code) {
520 7
        $cx['partials'][$p] = $code;
521 7
    }
522
523
    /* For single custom helpers.
524
     *
525
     * @param array<string,array|string|integer> $cx render time context for lightncandy
526
     * @param string $ch the name of custom helper to be executed
527
     * @param array<array|string|integer>|string|integer|null $vars variables for the helper
528
     * @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
529
     * @param array<string,array|string|integer> $_this current rendering context for the helper
530
     *
531
     * @return string The rendered string of the token
532
     */
533 119
    public static function hbch($cx, $ch, $vars, $op, &$_this) {
0 ignored issues
show
Unused Code introduced by
The parameter $op 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...
534 119
        if (isset($cx['blparam'][0][$ch])) {
535 1
            return $cx['blparam'][0][$ch];
536
        }
537
538
        $options = array(
539 119
            'name' => $ch,
540 119
            'hash' => $vars[1],
541 119
            'contexts' => count($cx['scopes']) ? $cx['scopes'] : array(null),
542 119
            'fn.blockParams' => 0,
543 119
            '_this' => &$_this
544
        );
545
546 119
        if ($cx['flags']['spvar']) {
547 114
            $options['data'] = $cx['sp_vars'];
548
        }
549
550 119
        return static::exch($cx, $ch, $vars, $options);
551
    }
552
553
    /**
554
     * For block custom helpers.
555
     *
556
     * @param array<string,array|string|integer> $cx render time context for lightncandy
557
     * @param string $ch the name of custom helper to be executed
558
     * @param array<array|string|integer>|string|integer|null $vars variables for the helper
559
     * @param array<string,array|string|integer> $_this current rendering context for the helper
560
     * @param boolean $inverted the logic will be inverted
561
     * @param Closure|null $cb callback function to render child context
562
     * @param Closure|null $else callback function to render child context when {{else}}
563
     *
564
     * @return string The rendered string of the token
565
     */
566 56
    public static function hbbch($cx, $ch, $vars, &$_this, $inverted, $cb, $else = null) {
567
        $options = array(
568 56
            'name' => $ch,
569 56
            'hash' => $vars[1],
570 56
            'contexts' => count($cx['scopes']) ? $cx['scopes'] : array(null),
571 56
            'fn.blockParams' => 0,
572 56
            '_this' => &$_this,
573
        );
574
575 56
        if ($cx['flags']['spvar']) {
576 52
            $options['data'] = $cx['sp_vars'];
577
        }
578
579 56
        if (isset($vars[2])) {
580 3
            $options['fn.blockParams'] = count($vars[2]);
581
        }
582
583
        // $invert the logic
584 56
        if ($inverted) {
585
            $tmp = $else;
586
            $else = $cb;
587
            $cb = $tmp;
588
        }
589
590
        $options['fn'] = function ($context = '_NO_INPUT_HERE_', $data = null) use ($cx, &$_this, $cb, $options, $vars) {
591 45
            if ($cx['flags']['echo']) {
592
                ob_start();
593
            }
594 45
            if (isset($data['data'])) {
595 6
                $old_spvar = $cx['sp_vars'];
596 6
                $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $data['data'], array('_parent' => $old_spvar));
597
            }
598 45
            $ex = false;
599 45
            if (isset($data['blockParams']) && isset($vars[2])) {
600 3
                $ex = array_combine($vars[2], array_slice($data['blockParams'], 0, count($vars[2])));
601 3
                array_unshift($cx['blparam'], $ex);
602 43
            } else if (isset($cx['blparam'][0])) {
603 1
                $ex = $cx['blparam'][0];
604
            }
605 45
            if (($context === '_NO_INPUT_HERE_') || ($context === $_this)) {
606 28
                $ret = $cb($cx, is_array($ex) ? static::m($cx, $_this, $ex) : $_this);
607
            } else {
608 20
                $cx['scopes'][] = $_this;
609 20
                $ret = $cb($cx, is_array($ex) ? static::m($cx, $context, $ex) : $context);
610 20
                array_pop($cx['scopes']);
611
            }
612 45
            if (isset($data['data'])) {
613 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...
614
            }
615 45
            return $cx['flags']['echo'] ? ob_get_clean() : $ret;
616
        };
617
618 56
        if ($else) {
619
            $options['inverse'] = function ($context = '_NO_INPUT_HERE_') use ($cx, $_this, $else) {
620 6
                if ($cx['flags']['echo']) {
621
                    ob_start();
622
                }
623 6
                if ($context === '_NO_INPUT_HERE_') {
624 1
                    $ret = $else($cx, $_this);
625
                } else {
626 5
                    $cx['scopes'][] = $_this;
627 5
                    $ret = $else($cx, $context);
628 5
                    array_pop($cx['scopes']);
629
                }
630 6
                return $cx['flags']['echo'] ? ob_get_clean() : $ret;
631 10
            };
632
        } else {
633
            $options['inverse'] = function () {
634
                return '';
635
            };
636
        }
637
638 56
        return static::exch($cx, $ch, $vars, $options);
639
    }
640
641
    /**
642
     * Execute custom helper with prepared options
643
     *
644
     * @param array<string,array|string|integer> $cx render time context for lightncandy
645
     * @param string $ch the name of custom helper to be executed
646
     * @param array<array|string|integer>|string|integer|null $vars variables for the helper
647
     * @param array<string,array|string|integer> $option the options object
0 ignored issues
show
Documentation introduced by
There is no parameter named $option. Did you maybe mean $options?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
648
     *
649
     * @return string The rendered string of the token
650
     */
651 165
    public static function exch($cx, $ch, $vars, &$options) {
652 165
        $args = $vars[0];
653 165
        $args[] = $options;
654 165
        $e = null;
655 165
        $r = true;
656
657
        try {
658 165
            $r = call_user_func_array($cx['helpers'][$ch], $args);
659 2
        } catch (\Exception $E) {
660 2
            $e = "Runtime: call custom helper '$ch' error: " . $E->getMessage();
661
        }
662
663 165
        if($e !== null) {
664 2
            static::err($cx, $e);
665
        }
666
667 164
        return $r;
668
    }
669
}
670