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 ( 731f7f...62a245 )
by Zordius
06:59
created

Runtime::m()   B

Complexity

Conditions 8
Paths 5

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 8

Importance

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