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 ( 24d0ed...428a72 )
by Zordius
03:29
created

Runtime::p()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 14
ccs 8
cts 8
cp 1
rs 9.2
cc 4
eloc 8
nc 6
nop 5
crap 4
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 385
    public static function v($cx, $in, $base, $path, $args = null) {
132 385
        $count = count($cx['scopes']);
133 385
        while ($base) {
134 349
            $v = $base;
135 349
            foreach ($path as $name) {
136 349
                if (is_array($v) && isset($v[$name])) {
137 344
                    $v = $v[$name];
138 344
                    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 349
            if (isset($v)) {
157 338
                if ($v instanceof \Closure) {
158 30
                    if ($cx['flags']['mustlam'] || $cx['flags']['lambda']) {
159 30
                        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 11
                            $A = array($in);
164
                        }
165 30
                        $v = call_user_func_array($v, $A);
166
                    }
167
                }
168 338
                return $v;
169
            }
170 31
            $count--;
171
            switch ($count) {
172 31
                case -1:
173 30
                    $base = $cx['sp_vars']['root'];
174 30
                    break;
175 6
                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 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...
207 64
        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 htmlentities(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 317
    public static function encq($cx, $var) {
264 317
        if ($var instanceof \LightnCandy\SafeString) {
265 3
            return (string)$var;
266
        }
267
268 314
        return str_replace(array('=', '`', '&#039;'), array('&#x3D;', '&#x60;', '&#x27;'), htmlentities(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 158
    public static function sec($cx, $v, $bp, $in, $each, $cb, $else = null) {
310 158
        $push = ($in !== $v) || $each;
311
312 158
        $isAry = is_array($v) || ($v instanceof \ArrayObject);
313 158
        $isTrav = $v instanceof \Traversable;
314 158
        $loop = $each;
315 158
        $keys = null;
316 158
        $last = null;
317 158
        $isObj = false;
318
319 158
        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 156
        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 156
        if (($loop && $isAry) || $isTrav) {
332 98
            if ($each && !$isTrav) {
333
                // Detect input type is object or not when never done once
334 44
                if ($keys == null) {
335 44
                    $keys = array_keys($v);
336 44
                    $isObj = (count(array_diff_key($v, array_keys($keys))) > 0);
337
                }
338
            }
339 98
            $ret = array();
340 98
            if ($push) {
341 96
                $cx['scopes'][] = $in;
342
            }
343 98
            $i = 0;
344 98
            if ($cx['flags']['spvar']) {
345 89
                $old_spvar = $cx['sp_vars'];
346 89
                $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $old_spvar, array('_parent' => $old_spvar));
347 89
                if (!$isTrav) {
348 88
                    $last = count($keys) - 1;
349
                }
350
            }
351
352 98
            $isSparceArray = $isObj && (count(array_filter(array_keys($v), 'is_string')) == 0);
353 98
            foreach ($v as $index => $raw) {
354 91
                if ($cx['flags']['spvar']) {
355 83
                    $cx['sp_vars']['first'] = ($i === 0);
356 83
                    $cx['sp_vars']['last'] = ($i == $last);
357 83
                    $cx['sp_vars']['key'] = $index;
358 83
                    $cx['sp_vars']['index'] = $isSparceArray ? $index : $i;
359 83
                    $i++;
360
                }
361 91
                if (isset($bp[0])) {
362 1
                    $raw = static::m($cx, $raw, array($bp[0] => $raw));
363
                }
364 91
                if (isset($bp[1])) {
365 1
                    $raw = static::m($cx, $raw, array($bp[1] => $cx['sp_vars']['index']));
366
                }
367 91
                $ret[] = $cb($cx, $raw);
368
            }
369 97
            if ($cx['flags']['spvar']) {
370 88
                if ($isObj) {
371 14
                    unset($cx['sp_vars']['key']);
372
                } else {
373 76
                    unset($cx['sp_vars']['last']);
374
                }
375 88
                unset($cx['sp_vars']['index']);
376 88
                unset($cx['sp_vars']['first']);
377 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...
378
            }
379 97
            if ($push) {
380 95
                array_pop($cx['scopes']);
381
            }
382 97
            return join('', $ret);
383
        }
384 60
        if ($each) {
385 2
            if ($else !== null) {
386 1
                $ret = $else($cx, $v);
387 1
                return $ret;
388
            }
389 2
            return '';
390
        }
391 59
        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 49
        if ($v === true) {
403 22
            return $cb($cx, $in);
404
        }
405
406 28
        if (($v !== null) && ($v !== false)) {
407 5
            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 22
    public static function wi($cx, $v, $bp, $in, $cb, $else = null) {
436 22
        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 22
        if (($v === false) || ($v === null)) {
440 3
            return $else ? $else($cx, $in) : '';
441
        }
442 20
        $cx['scopes'][] = $in;
443 20
        $ret = $cb($cx, $v);
444 20
        array_pop($cx['scopes']);
445 20
        return $ret;
446
    }
447
448
    /**
449
     * Get merged context.
450
     *
451
     * @param array<string,array|string|integer> $cx render time context
452
     * @param array<array|string|integer>|string|integer|null $a the context to be merged
453
     * @param array<array|string|integer>|string|integer|null $b the new context to overwrite
454
     *
455
     * @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...
456
     *
457
     */
458 83
    public static function m($cx, $a, $b) {
459 83
        if (is_array($b)) {
460 83
            if ($a === null) {
461 7
                return $b;
462 76
            } else if (is_array($a)) {
463 73
                return array_merge($a, $b);
464 3
            } else if (($cx['flags']['method'] || $cx['flags']['prop']) && is_object($a)) {
465 1
                foreach ($b as $i => $v) {
466 1
                    $a->$i = $v;
467
                }
468
            }
469
        }
470 3
        return $a;
471
    }
472
473
    /**
474
     * For {{> partial}} .
475
     *
476
     * @param array<string,array|string|integer> $cx render time context
477
     * @param string $p partial name
478
     * @param array<array|string|integer>|string|integer|null $v value to be the new context
479
     *
480
     * @return string The rendered string of the partial
481
     *
482
     */
483 79
    public static function p($cx, $p, $v, $pid, $sp = '') {
484 79
        if ($p === '@partial-block') {
485 6
            $p = "$p" . ($pid > 0 ? $pid : $cx['partialid']);
486
        }
487
488 79
        if (!isset($cx['partials'][$p])) {
489 2
            static::err($cx, "Can not find partial named as '$p' !!");
490 1
            return '';
491
        }
492
493 77
        $cx['partialid'] = $pid;
494
495 77
        return call_user_func($cx['partials'][$p], $cx, static::m($cx, $v[0][0], $v[1]), $sp);
496
    }
497
498
    /**
499
     * For {{#* inlinepartial}} .
500
     *
501
     * @param array<string,array|string|integer> $cx render time context
502
     * @param string $p partial name
503
     * @param Closure $code the compiled partial code
504
     *
505
     */
506 7
    public static function in(&$cx, $p, $code) {
507 7
        $cx['partials'][$p] = $code;
508 7
    }
509
510
    /**
511
     * For custom helpers.
512
     *
513
     * @param array<string,array|string|integer> $cx render time context
514
     * @param string $ch the name of custom helper to be executed
515
     * @param array<array|string|integer>|string|integer|null $vars variables for the helper
516
     * @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
517
     * @param boolean $inverted the logic will be inverted
518
     * @param Closure|null $cb callback function to render child context
519
     * @param Closure|null $else callback function to render child context when {{else}}
520
     *
521
     * @return string The rendered string of the token
522
     */
523 150
    public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null) {
524 150
        $isBlock = (is_object($cb) && ($cb instanceof \Closure));
525
526 150
        if (isset($cx['blparam'][0][$ch])) {
527 1
            return $cx['blparam'][0][$ch];
528
        }
529
530 150
        $args = $vars[0];
531
        $options = array(
532 150
            'name' => $ch,
533 150
            'hash' => $vars[1],
534 150
            'contexts' => count($cx['scopes']) ? $cx['scopes'] : array(null),
535 150
            'fn.blockParams' => 0,
536
        );
537
538 150
        if ($isBlock) {
539 49
            $options['_this'] = &$op;
540
        } else {
541 111
            $options['_this'] = &$inverted;
542
        }
543
544 150
        if (isset($vars[2])) {
545 3
            $options['fn.blockParams'] = count($vars[2]);
546
        }
547
548
        // $invert the logic
549 150
        if ($inverted) {
550 73
            $tmp = $else;
551 73
            $else = $cb;
552 73
            $cb = $tmp;
553
        }
554
555 150
        if ($isBlock) {
556
            $options['fn'] = function ($context = '_NO_INPUT_HERE_', $data = null) use ($cx, &$op, $cb, $options, $vars) {
557 40
                if ($cx['flags']['echo']) {
558
                    ob_start();
559
                }
560 40
                if (isset($data['data'])) {
561 6
                    $old_spvar = $cx['sp_vars'];
562 6
                    $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $data['data'], array('_parent' => $old_spvar));
563
                }
564 40
                $ex = false;
565 40
                if (isset($data['blockParams']) && isset($vars[2])) {
566 3
                    $ex = array_combine($vars[2], array_slice($data['blockParams'], 0, count($vars[2])));
567 3
                    array_unshift($cx['blparam'], $ex);
568 38
                } else if (isset($cx['blparam'][0])) {
569 1
                    $ex = $cx['blparam'][0];
570
                }
571 40
                if (($context === '_NO_INPUT_HERE_') || ($context === $op)) {
572 24
                    $ret = $cb($cx, is_array($ex) ? static::m($cx, $op, $ex) : $op);
573
                } else {
574 19
                    $cx['scopes'][] = $op;
575 19
                    $ret = $cb($cx, is_array($ex) ? static::m($cx, $context, $ex) : $context);
576 19
                    array_pop($cx['scopes']);
577
                }
578 40
                if (isset($data['data'])) {
579 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...
580
                }
581 40
                return $cx['flags']['echo'] ? ob_get_clean() : $ret;
582
            };
583
        }
584
585 150
        if ($else) {
586 4
            $options['inverse'] = function ($context = '_NO_INPUT_HERE_') use ($cx, $op, $else) {
587 4
                if ($cx['flags']['echo']) {
588
                    ob_start();
589
                }
590 4
                if ($context === '_NO_INPUT_HERE_') {
591
                    $ret = $else($cx, $op);
592
                } else {
593 4
                    $cx['scopes'][] = $op;
594 4
                    $ret = $else($cx, $context);
595 4
                    array_pop($cx['scopes']);
596
                }
597 4
                return $cx['flags']['echo'] ? ob_get_clean() : $ret;
598
            };
599
        }
600
601 150
        if ($cx['flags']['spvar']) {
602 145
            $options['data'] = $cx['sp_vars'];
603
        }
604
605 150
        $args[] = $options;
606 150
        $e = null;
607 150
        $r = true;
608
609
        try {
610 150
            $r = call_user_func_array($cx['helpers'][$ch], $args);
611 2
        } catch (\Exception $E) {
612 2
            $e = "Runtime: call custom helper '$ch' error: " . $E->getMessage();
613
        }
614
615 150
        if($e !== null) {
616 2
            static::err($cx, $e);
617
        }
618
619 149
        return $r;
620
    }
621
}
622
623