Closed mikemherron closed 7 years ago
ugh, Github where's my answer gone to!? Actually I've answered this issue yesterday already, but seems to have been gone :-(
So yes, this is actually expected behaviour, ... so I agree that it might not seem obvious (and probably is unwanted even).
The point is that objects are exposed to JavaScript by an small object simply delegating to the real PHP object. This is if you access one of the properties from JavaScript you're actually "just in time" accessing the PHP object. If you're writing to the object from JavaScript it's actually persisted on the PHP object and you are able to see the change on PHP side:
root@8f794daab180:/# php -a
Interactive mode enabled
php > $v8 = new V8Js();
php > $foo = new stdClass();
php > $foo->blar = 42;
php > $v8->foo = $foo;
php > $v8->executeString('PHP.foo.blub = 23;');
php > var_dump($foo);
object(stdClass)#2 (2) {
["blar"]=>
int(42)
["blub"]=>
int(23)
}
However this isn't true for arrays. An array is exported to a real JavaScript array, and all elements are immediately exported. If you change the JavaScript array later on it doesn't affect the PHP array.
root@8f794daab180:/# php -a
Interactive mode enabled
php > $v8 = new V8Js();
php > $foo = [ 'blar' => 42 ];
php > $v8->foo = $foo;
php > $v8->executeString('PHP.foo.blub = 23; ');
php > var_dump($foo);
array(1) {
["blar"]=>
int(42)
}
php > $v8->executeString('var_dump(PHP.foo); ');
array (2) {
["blar"] =>
int(42)
["blub"] =>
int(23)
}
... the var_dump on JavaScript side reflects the change; while the PHP side doesn't.
Now applying this knowledge to your code sample:
var obj = Test.provider.getItemsInObject();
var result = obj.items.push('three');
print ('Result of push:' + result + '\\n');
for( var i=0;i!=obj.items.length;i++) {
print('Item :' + obj.items[i] + '\\n');
}
Test.provider.getItemsInObject()
returns a PHP object, which is wrapped to a JS object delegating to itobj.items
accesses the property on the PHP object and yields a PHP array, which is converted to a JavaScript array element by elementpush
adds one element to aforesaid JavaScript array (leaving the PHP array unmodified)obj.items.length
again retrieves the items
property of the PHP object (through the obj
delegate), again converting the PHP array to JavaScript... however as the PHP array is unmodified you don't see the modification by the push
call
Hope that at least makes clear what's going on inside V8Js :)
@stesie Thanks for the detailed answer and explanation. I had a hunch that the problem was going to be somewhere in the mapping process between JavaScript and PHP. Your explanation makes sense, and I can workaround the behaviour. Happy to have the issue closed and thanks again for taking the time to explain is such detail.
This is probably easier to show than explain. See below test script. The final example adds an item to the end of an array returned from a php object passed to v8. The item added however does not appear when iterating through the same array. The return of the push call is 3, as if the item has been added. Appending on to the array DOES work if the array is passed directly from PHP.
This outputs:
Is this expected behaviour?