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 ( 1f1050...426291 )
by Zordius
02:07
created

Runtime::p()   B

Complexity

Conditions 7
Paths 36

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 7

Importance

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