1
|
|
|
<?php declare(strict_types=1); |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the pinepain/js-sandbox PHP library. |
5
|
|
|
* |
6
|
|
|
* Copyright (c) 2016-2017 Bogdan Padalko <[email protected]> |
7
|
|
|
* |
8
|
|
|
* Licensed under the MIT license: http://opensource.org/licenses/MIT |
9
|
|
|
* |
10
|
|
|
* For the full copyright and license information, please view the |
11
|
|
|
* LICENSE file that was distributed with this source or visit |
12
|
|
|
* http://opensource.org/licenses/MIT |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
|
16
|
|
|
namespace Pinepain\JsSandbox\Wrappers; |
17
|
|
|
|
18
|
|
|
|
19
|
|
|
use V8\ArrayObject; |
20
|
|
|
use V8\Context; |
21
|
|
|
use V8\IntegerValue; |
22
|
|
|
use V8\Isolate; |
23
|
|
|
use V8\ObjectValue; |
24
|
|
|
|
25
|
|
|
|
26
|
|
|
class ArrayWrapper implements WrapperInterface, WrapperAwareInterface |
27
|
|
|
{ |
28
|
|
|
use WrapperAwareTrait; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @param Isolate $isolate |
32
|
|
|
* @param Context $context |
33
|
|
|
* @param array $value |
34
|
|
|
* |
35
|
|
|
* @return ArrayObject|ObjectValue |
36
|
|
|
* @throws WrapperException |
37
|
|
|
*/ |
38
|
|
|
public function wrap(Isolate $isolate, Context $context, $value) |
39
|
|
|
{ |
40
|
|
|
// NOTE: js arrays, unlike php, will have gaps if indices are not monotonically increasing from 0. |
41
|
|
|
// Also, non-integer keys does not affect array length as they become properties of array object, |
42
|
|
|
// so if we have associative array, we will wrap it as object. |
43
|
|
|
if ($this->isAssoc($value)) { |
44
|
|
|
return $this->wrapAsObject($isolate, $context, $value); |
45
|
|
|
} else { |
46
|
|
|
return $this->wrapAsArray($isolate, $context, $value); |
47
|
|
|
} |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
private function isAssoc(array $value) |
51
|
|
|
{ |
52
|
|
|
if (!$value) { |
|
|
|
|
53
|
|
|
return false; |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
sort($value); |
57
|
|
|
|
58
|
|
|
return array_keys($value) != range(0, count($value) - 1); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
View Code Duplication |
private function wrapAsArray(Isolate $isolate, Context $context, array $value): ArrayObject |
|
|
|
|
62
|
|
|
{ |
63
|
|
|
$ret = new ArrayObject($context); |
64
|
|
|
// TODO: write test to ensure items have the same order, sort() was breaking that order |
65
|
|
|
$key = 0; |
66
|
|
|
foreach ($value as $val) { |
67
|
|
|
$js_val = $this->wrapper->wrap($isolate, $context, $val); |
68
|
|
|
$js_key = new IntegerValue($isolate, $key++); |
69
|
|
|
$ret->set($context, $js_key, $js_val); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
return $ret; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
View Code Duplication |
private function wrapAsObject(Isolate $isolate, Context $context, array $value): ObjectValue |
|
|
|
|
76
|
|
|
{ |
77
|
|
|
$ret = new ObjectValue($context); |
78
|
|
|
|
79
|
|
|
foreach ($value as $key => $val) { |
80
|
|
|
$js_val = $this->wrapper->wrap($isolate, $context, $val); |
81
|
|
|
$js_key = $this->wrapper->wrap($isolate, $context, $key); |
82
|
|
|
$ret->set($context, $js_key, $js_val); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
return $ret; |
86
|
|
|
} |
87
|
|
|
} |
88
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.