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 ( 898ed8...ccf3f3 )
by Zordius
02:20
created

Runtime::raw()   D

Complexity

Conditions 9
Paths 23

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 9

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 31
ccs 17
cts 17
cp 1
rs 4.9091
cc 9
eloc 19
nc 23
nop 2
crap 9

1 Method

Rating   Name   Duplication   Size   Complexity  
A Runtime::encq() 0 7 2
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
     * LightnCandy runtime method for 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
     * LightnCandy runtime method for error
79
     *
80
     * @param array<string,array|string|integer> $cx render time context
81
     * @param string $err error message
82
     *
83
     * @throws \Exception
84
     */
85 11
    public static function err($cx, $err) {
86 11
        if ($cx['flags']['debug'] & static::DEBUG_ERROR_LOG) {
87 2
            error_log($err);
88 2
            return;
89
        }
90 9
        if ($cx['flags']['debug'] & static::DEBUG_ERROR_EXCEPTION) {
91 6
            throw new \Exception($err);
92
        }
93 3
    }
94
95
    /**
96
     * LightnCandy runtime method for missing data error.
97
     *
98
     * @param array<string,array|string|integer> $cx render time context
99
     * @param string $v expression
100
     */
101 5
    public static function miss($cx, $v) {
102 5
        static::err($cx, "Runtime: $v is not exist");
103 4
    }
104
105
    /**
106
     * LightnCandy runtime method for 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
     * LightnCandy runtime method for variable lookup. It is slower and 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
     * LightnCandy runtime method for {{#if var}}.
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
     * LightnCandy runtime method for {{^var}} inverted section.
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
     * LightnCandy runtime method 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
     */
242 45
    public static function enc($cx, $var) {
243 45
        if ($var instanceof SafeString) {
244
            return (string)$var;
245
        }
246
247 45
        return htmlentities(static::raw($cx, $var), ENT_QUOTES, 'UTF-8');
248
    }
249
250
    /**
251
     * LightnCandy runtime method for {{var}} , and deal with single quote to same as 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 321
    public static function encq($cx, $var) {
264 321
        if ($var instanceof SafeString) {
265 3
            return (string)$var;
266
        }
267
268 318
        return str_replace(array('=', '`', '&#039;'), array('&#x3D;', '&#x60;', '&#x27;'), htmlentities(static::raw($cx, $var), ENT_QUOTES, 'UTF-8'));
269
    }
270
271
    /**
272
     * LightnCandy runtime method for {{#var}} section.
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 160
    public static function sec($cx, $v, $bp, $in, $each, $cb, $else = null) {
310 160
        $push = ($in !== $v) || $each;
311
312 160
        $isAry = is_array($v) || ($v instanceof \ArrayObject);
313 160
        $isTrav = $v instanceof \Traversable;
314 160
        $loop = $each;
315 160
        $keys = null;
316 160
        $last = null;
317 160
        $isObj = false;
318
319 160
        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 158
        if (!$loop && $isAry) {
326 65
            $keys = array_keys($v);
327 65
            $loop = (count(array_diff_key($v, array_keys($keys))) == 0);
328 65
            $isObj = !$loop;
329
        }
330
331 158
        if ($cx['flags']['mustlam'] && ($v instanceof \Closure)) {
332
            static::err($cx, 'Do not support Section Lambdas!');
333
        }
334
335 158
        if (($loop && $isAry) || $isTrav) {
336 100
            if ($each && !$isTrav) {
337
                // Detect input type is object or not when never done once
338 45
                if ($keys == null) {
339 45
                    $keys = array_keys($v);
340 45
                    $isObj = (count(array_diff_key($v, array_keys($keys))) > 0);
341
                }
342
            }
343 100
            $ret = array();
344 100
            if ($push) {
345 98
                $cx['scopes'][] = $in;
346
            }
347 100
            $i = 0;
348 100
            if ($cx['flags']['spvar']) {
349 89
                $old_spvar = $cx['sp_vars'];
350 89
                $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $old_spvar, array('_parent' => $old_spvar));
351 89
                if (!$isTrav) {
352 88
                    $last = count($keys) - 1;
353
                }
354
            }
355
356 100
            $isSparceArray = $isObj && (count(array_filter(array_keys($v), 'is_string')) == 0);
357 100
            foreach ($v as $index => $raw) {
358 93
                if ($cx['flags']['spvar']) {
359 83
                    $cx['sp_vars']['first'] = ($i === 0);
360 83
                    $cx['sp_vars']['last'] = ($i == $last);
361 83
                    $cx['sp_vars']['key'] = $index;
362 83
                    $cx['sp_vars']['index'] = $isSparceArray ? $index : $i;
363 83
                    $i++;
364
                }
365 93
                if (isset($bp[0])) {
366 1
                    $raw = static::m($cx, $raw, array($bp[0] => $raw));
367
                }
368 93
                if (isset($bp[1])) {
369 1
                    $raw = static::m($cx, $raw, array($bp[1] => $cx['sp_vars']['index']));
370
                }
371 93
                $ret[] = $cb($cx, $raw);
372
            }
373 99
            if ($cx['flags']['spvar']) {
374 88
                if ($isObj) {
375 14
                    unset($cx['sp_vars']['key']);
376
                } else {
377 76
                    unset($cx['sp_vars']['last']);
378
                }
379 88
                unset($cx['sp_vars']['index']);
380 88
                unset($cx['sp_vars']['first']);
381 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...
382
            }
383 99
            if ($push) {
384 97
                array_pop($cx['scopes']);
385
            }
386 99
            return join('', $ret);
387
        }
388 61
        if ($each) {
389 2
            if ($else !== null) {
390 1
                $ret = $else($cx, $v);
391 1
                return $ret;
392
            }
393 2
            return '';
394
        }
395 60
        if ($isAry) {
396 11
            if ($push) {
397 10
                $cx['scopes'][] = $in;
398
            }
399 11
            $ret = $cb($cx, $v);
400 11
            if ($push) {
401 10
                array_pop($cx['scopes']);
402
            }
403 11
            return $ret;
404
        }
405
406 50
        if ($v === true) {
407 22
            return $cb($cx, $in);
408
        }
409
410 29
        if (($v !== null) && ($v !== false)) {
411 6
            return $cb($cx, $v);
412
        }
413
414 24
        if ($else !== null) {
415 10
            $ret = $else($cx, $in);
416 10
            return $ret;
417
        }
418
419 15
        return '';
420
    }
421
422
    /**
423
     * LightnCandy runtime method for {{#with var}} .
424
     *
425
     * @param array<string,array|string|integer> $cx render time context
426
     * @param array<array|string|integer>|string|integer|null $v value to be the new context
427
     * @param array<array|string|integer>|string|integer|null $in input data with current scope
428
     * @param array<string>|null $bp block parameters
429
     * @param Closure $cb callback function to render child context
430
     * @param Closure|null $else callback function to render child context when {{else}}
431
     *
432
     * @return string The rendered string of the token
433
     *
434
     * @expect '' when input array(), false, null, false, function () {return 'A';}
435
     * @expect '' when input array(), null, null, null, function () {return 'A';}
436
     * @expect '{"a":"b"}' when input array(), array('a'=>'b'), null, array('a'=>'c'), function ($c, $i) {return json_encode($i);}
437
     * @expect '-b=' when input array(), 'b', null, array('a'=>'b'), function ($c, $i) {return "-$i=";}
438
     */
439 25
    public static function wi($cx, $v, $bp, $in, $cb, $else = null) {
440 25
        if (isset($bp[0])) {
441 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...
442
        }
443 25
        if (($v === false) || ($v === null)) {
444 4
            return $else ? $else($cx, $in) : '';
445
        }
446 22
        $cx['scopes'][] = $in;
447 22
        $ret = $cb($cx, $v);
448 22
        array_pop($cx['scopes']);
449 22
        return $ret;
450
    }
451
452
    /**
453
     * LightnCandy runtime method to 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 82
    public static function m($cx, $a, $b) {
463 82
        if (is_array($b)) {
464 82
            if ($a === null) {
465 7
                return $b;
466 75
            } else if (is_array($a)) {
467 72
                return array_merge($a, $b);
468 3
            } else if (($cx['flags']['method'] || $cx['flags']['prop']) && is_object($a)) {
469 1
                foreach ($b as $i => $v) {
470 1
                    $a->$i = $v;
471
                }
472
            }
473
        }
474 3
        return $a;
475
    }
476
477
    /**
478
     * LightnCandy runtime method 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 77
    public static function p($cx, $p, $v, $sp = '') {
488 77
        if (!isset($cx['partials'][$p])) {
489 1
            static::err($cx, "Can not find partial named as '$p' !!");
490
            return '';
491
        }
492
493 76
        return call_user_func($cx['partials'][$p], $cx, static::m($cx, $v[0][0], $v[1]), $sp);
494
    }
495
496
    /**
497
     * LightnCandy runtime method for inline partial.
498
     *
499
     * @param array<string,array|string|integer> $cx render time context
500
     * @param string $p partial name
501
     * @param Closure $code the compiled partial code
502
     *
503
     */
504 7
    public static function in(&$cx, $p, $code) {
505 7
        $cx['partials'][$p] = $code;
506 7
    }
507
508
    /**
509
     * LightnCandy runtime method for Handlebars.js style custom helpers.
510
     *
511
     * @param array<string,array|string|integer> $cx render time context
512
     * @param string $ch the name of custom helper to be executed
513
     * @param array<array|string|integer>|string|integer|null $vars variables for the helper
514
     * @param string $op the name of variable resolver. should be one of: 'raw', 'enc', or 'encq'.
515
     * @param boolean $inverted the logic will be inverted
516
     * @param Closure|null $cb callback function to render child context
517
     * @param Closure|null $else callback function to render child context when {{else}}
518
     *
519
     * @return string The rendered string of the token
520
     */
521 165
    public static function hbch($cx, $ch, $vars, $op, $inverted, $cb = null, $else = null) {
522 165
        $isBlock = (is_object($cb) && ($cb instanceof \Closure));
523
524 165
        if (isset($cx['blparam'][0][$ch])) {
525 1
            return $cx['blparam'][0][$ch];
526
        }
527
528 165
        $args = $vars[0];
529
        $options = array(
530 165
            'name' => $ch,
531 165
            'hash' => $vars[1],
532 165
            'contexts' => count($cx['scopes']) ? $cx['scopes'] : array(null),
533 165
            'fn.blockParams' => 0,
534
        );
535
536 165
        if ($isBlock) {
537 58
            $options['_this'] = &$op;
538
        } else {
539 117
            $options['_this'] = &$inverted;
540
        }
541
542 165
        if (isset($vars[2])) {
543 3
            $options['fn.blockParams'] = count($vars[2]);
544
        }
545
546
        // $invert the logic
547 165
        if ($inverted) {
548 78
            $tmp = $else;
549 78
            $else = $cb;
550 78
            $cb = $tmp;
551
        }
552
553 165
        if ($isBlock) {
554
            $options['fn'] = function ($context = '_NO_INPUT_HERE_', $data = null) use ($cx, &$op, $cb, $options, $vars) {
555 46
                if ($cx['flags']['echo']) {
556 6
                    ob_start();
557
                }
558 46
                if (isset($data['data'])) {
559 6
                    $old_spvar = $cx['sp_vars'];
560 6
                    $cx['sp_vars'] = array_merge(array('root' => $old_spvar['root']), $data['data'], array('_parent' => $old_spvar));
561
                }
562 46
                $ex = false;
563 46
                if (isset($data['blockParams']) && isset($vars[2])) {
564 3
                    $ex = array_combine($vars[2], array_slice($data['blockParams'], 0, count($vars[2])));
565 3
                    array_unshift($cx['blparam'], $ex);
566 44
                } else if (isset($cx['blparam'][0])) {
567 1
                    $ex = $cx['blparam'][0];
568
                }
569 46
                if (($context === '_NO_INPUT_HERE_') || ($context === $op)) {
570 27
                    $ret = $cb($cx, is_array($ex) ? static::m($cx, $op, $ex) : $op);
571
                } else {
572 22
                    $cx['scopes'][] = $op;
573 22
                    $ret = $cb($cx, is_array($ex) ? static::m($cx, $context, $ex) : $context);
574 22
                    array_pop($cx['scopes']);
575
                }
576 46
                if (isset($data['data'])) {
577 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...
578
                }
579 46
                return $cx['flags']['echo'] ? ob_get_clean() : $ret;
580
            };
581
        }
582
583 165
        if ($else) {
584 7
            $options['inverse'] = function ($context = '_NO_INPUT_HERE_') use ($cx, $op, $else) {
585 7
                if ($cx['flags']['echo']) {
586 3
                    ob_start();
587
                }
588 7
                if ($context === '_NO_INPUT_HERE_') {
589 2
                    $ret = $else($cx, $op);
590
                } else {
591 5
                    $cx['scopes'][] = $op;
592 5
                    $ret = $else($cx, $context);
593 5
                    array_pop($cx['scopes']);
594
                }
595 7
                return $cx['flags']['echo'] ? ob_get_clean() : $ret;
596
            };
597
        }
598
599 165
        if ($cx['flags']['spvar']) {
600 151
            $options['data'] = $cx['sp_vars'];
601
        }
602
603 165
        $args[] = $options;
604 165
        $e = null;
605 165
        $r = true;
606
607
        try {
608 165
            $r = call_user_func_array($cx['helpers'][$ch], $args);
609 2
        } catch (\Exception $E) {
610 2
            $e = "Runtime: call custom helper '$ch' error: " . $E->getMessage();
611
        }
612
613 165
        if($e !== null) {
614 2
            static::err($cx, $e);
615
        }
616
617 164
        return $r;
618
    }
619
}
620
621