Page 1 of 1

Curious feature for onEnteringState and length of arrays in args

Posted: 18 August 2020, 06:07
by CuriousTerran
On the game php side my state uses an argument function to pass valid locations to play like the reversi tutorial.
I build the locations in php scetched like this
$objData = self::getObjectListFromDB(...)
$objArr = array();
foreach ($objData as $idx => $Data)
{
...do some calcs and filter entries to valid ones...
$objArr[] = array('key1'=>$val1, 'key2'=>$val2,....)
}
$objArr is an array of arrays with indices/keys of 0,1,2,... that is returned from the argument function.

Then, this argument function is named as the "args" function in the state file, so this array shows up on the java side as part of onEnteringState.
Most of the time this works, I see objArr and it has the correct contents and important for my checks in onEnteringState , I can get the length of objArr from args.objArr.length.
However, on the php side I have another filtering step where I remove array elements from $objArr using the php unset() function. This again works most of the time on the js side and I get the correct length from args.objArr.length.

However, there is catch, if on the php side I use unset() on the first element of $objArr (e.g., unset($objArr[0])), then on the js side args.objArr.length becomes 'undefined' :shock: even if there are plenty of elements left in $objArr. This has caused some deal of hunting down this oddity since unset() in php does not reindex the entries after removing one. I am guessing that something is not quite correct in the hand off between php and js for this scenario.

Summary: avoid unset() for arrays generated in the argument function on the php side handed over to javascript. The length property of the array can become undefined in onEnteringState when you don't expect it to.

Re: Curious feature for onEnteringState and length of arrays in args

Posted: 18 August 2020, 07:41
by Tisaac
My advice : always do an array_values on the backend if you want to make sure the frontend will parse it as an array and not à generic object

Re: Curious feature for onEnteringState and length of arrays in args

Posted: 18 August 2020, 15:20
by CuriousTerran
Sounds like good advice. Thank you.

Re: Curious feature for onEnteringState and length of arrays in args

Posted: 19 August 2020, 16:30
by joezg
If your JS variable has no length property defined, it means it is not an array.
My first thought is that you received that value as an object on JS. And that is indeed the case.

I made a small test with this method on php side:

Code: Select all

    function TestRemove() {
        $arr = [0, 1, 2, 3, 4, 5, 6];

        unset($arr[3]);
        $this->notifyAllPlayers( "test", "", [
            "arr" => $arr
        ]);
    }
and a notification handler on JS side:

Code: Select all

notif_test: function(notif){
	console.log(notif.args);
 },
and indeed I saw an object in js console. If I remove unset statement I receive an array.

Values from php are encoded as json when transfered over HTTP and are decoded back to JS values on the client. JS (and similarly JSON) arrays cannot have missing indexes and are, in that case, treated as objects.

Php object: [0, 1, 2, 3, 4]
is received as array in JS: [0, 1, 2, 3, 4].

If you remove an element from php object, JSON (and JS) don't know how to treat a value other than as object:
{
0: 0,
1: 1,
3: 3,
4: 4
}

You can solve this problem on either side.
On php you can use array_values (as advised by tisaac) which is recommended way, but you can also use Object.values(notif.args.arr) on JS side to get all own properties of an object as array.