jsonmapper
jsonmapper copied to clipboard
Indirect modification of overloaded property ... has no effect
I am trying to map a JSON exported from MyBusiness (GBP) API.
I am getting this error:
Indirect modification of overloaded property Google\Service\MyBusinessBusinessInformation\Categories::$additionalCategories has no effect
Stack trace:
46
ErrorException
…/vendor/google/apiclient/src/Collection.php101
45
Illuminate\Foundation\Bootstrap\HandleExceptions handleError
…/vendor/google/apiclient/src/Collection.php101
44
Google\Collection offsetSet
…/vendor/netresearch/jsonmapper/src/JsonMapper.php436
43
JsonMapper mapArray
…/vendor/netresearch/jsonmapper/src/JsonMapper.php305
Is this a bug or it's known issues with a workaround? I haven't found anything in the docs.
JsonMapper usually works with public properties, or explicit setters, may even use reflection to gain access to protected/private properties.
The error message you are presenting points at the classes you are mapping to - I was unable to locate their source code, but it seems like they are using magic __get/__set in an inappropriate way. Can you illustrate that part more?
Also, please add the PHP version and JsonMapper version you are using. PHP changed quite a lot, that info is crucial!
Thanks! Sorry, this is the source code of the API client classes: https://github.com/googleapis/google-api-php-client/blob/main/src/Collection.php
Assuming that you want to map to a class that is effectively utilizing/inheriting from that collection, and the collection inherits from Model, this Model class only implements __get, but has nothing for __set. Still it isn't readonly, because it implements ArrayAccess and has offsetSet that obviously does something.
My guess here is that JsonMapper is misled about how to set a value into this class, guessing it may be able to call __set implicitly, triggering that error message.
My uneducated guess when looking at that Google code would be: Why would anyone attempt to map something to classes that utilize this complex code? I'd expect that either there is a client fully implementing HTTP request and mapping to PHP, and there it would make sense to have some complex data type handling inside. Or you do both steps on your own, and don't need this code at all. The Google client libs look like they support the first case. And I wouldn't expect you to be able to make them implement __set in their code.
Still I am uncertain what exactly you are trying to do here...?
My use case is:
- API response is requested+received fine (full structured, correctly mapped)
- Serialize this response using JSON structure and save into DB
- Unserialize this response from DB and try to work with it -> now effectively structured does not exist and we have stdClass at the best
So I would be using JsonMapper to restore the structure to the original API response. Sure I can create some custom iterator, but your class seemed to be of help.
On Wed, Nov 15, 2023 at 4:10 PM SvenRtbg @.***> wrote:
Assuming that you want to map to a class that is effectively utilizing/inheriting from that collection, and the collection inherits from Model, this Model class only implements __get, but has nothing for __set. Still it isn't readonly, because it implements ArrayAccess and has offsetSet that obviously does something.
My guess here is that JsonMapper is misled about how to set a value into this class, guessing it may be able to call __set implicitly, triggering that error message.
My uneducated guess when looking at that Google code would be: Why would anyone attempt to map something to classes that utilize this complex code? I'd expect that either there is a client fully implementing HTTP request and mapping to PHP, and there it would make sense to have some complex data type handling inside. Or you do both steps on your own, and don't need this code at all. The Google client libs look like they support the first case. And I wouldn't expect you to be able to make them implement __set in their code.
Still I am uncertain what exactly you are trying to do here...?
— Reply to this email directly, view it on GitHub https://github.com/cweiske/jsonmapper/issues/216#issuecomment-1812715673, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACBHPTMPUP3PJR3DOOKEYBLYETLNNAVCNFSM6AAAAAA7MPNJZGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMJSG4YTKNRXGM . You are receiving this because you authored the thread.Message ID: @.***>
Depending on your interoperability requirements, I'd suggest using PHPs own serialize() and unserialize() functions. They may also not work in certain situations because some PHP strutures like closures are not serializable, but they usually work for restoring the data structure. Keep in mind the string references class names, and unserializing to malicious class code is a security risk. The code isn't included, so if you can ensure the code referenced by name is correct, and nobody can access and modify the stored date (think: Sending the string to the user's browser and trusting it to be returned unaltered - that is asking for trouble!), it may be a viable alternative.
I just don't see a way to make google add this '__set()' to their library soon - and we established that you are doing something that probably wasn't expected by them.
I created a tiny example code that illustrates how to trigger that error message: https://3v4l.org/BhrB2
class Foo {
public function __get($key) {
return [new stdclass];
}
}
$c = new Foo();
$c->bar[0]->barbar = 1; # Triggers "Notice: Indirect modification of overloaded property Foo::$bar has no effect..."
var_dump($c);
And the output is an empty array. Adding __set isn't even fixing it. The code structure when writing to the barbar property is that a class has returned an array (which is passed by value - to keep it's change around, it should be saved somewhere), that contains an object that is getting a property changed on. The change to the object is not saved anywhere (and I guess you'd argue that I am not storing it in my example code - I am trying to grasp the problem, I would argue that reading from an object should not contain write operations in the first place, and that's what this error suggests is happening, I believe).
This modified code does work: https://3v4l.org/H6dK5
class Foo {
private array $i;
public function &__get($key) {
$this->i = [new stdclass];
return $this->i;
}
}
$c = new Foo();
$c->bar[0]->barbar = 1;
var_dump($c);
It forces the returned value to be passed by reference. That will create it's own class of crazyness if incorrectly applied, so I wouldn't recommend doing that either (still no way to make Google add it to their library anyways).
Thanks for the pointers, much appreciated! I will try to rebuild the code per your suggestions.
On Wed, Nov 15, 2023, 16:44 SvenRtbg @.***> wrote:
Depending on your interoperability requirements, I'd suggest using PHPs own serialize() and unserialize() functions. They may also not work in certain situations because some PHP strutures like closures are not serializable, but they usually work for restoring the data structure. Keep in mind the string references class names, and unserializing to malicious class code is a security risk. The code isn't included, so if you can ensure the code referenced by name is correct, and nobody can access and modify the stored date (think: Sending the string to the user's browser and trusting it to be returned unaltered - that is asking for trouble!), it may be a viable alternative.
I just don't see a way to make google add this '__set()' to their library soon - and we established that you are doing something that probably wasn't expected by them.
I created a tiny example code that illustrates how to trigger that error message: https://3v4l.org/BhrB2
class Foo { public function __get($key) { return [new stdclass]; } }
$c = new Foo(); $c->bar[0]->barbar = 1; # Triggers "Notice: Indirect modification of overloaded property Foo::$bar has no effect..."
var_dump($c);
And the output is an empty array. Adding __set isn't even fixing it. The code structure when writing to the barbar property is that a class has returned an array (which is passed by value - to keep it's change around, it should be saved somewhere), that contains an object that is getting a property changed on. The change to the object is not saved anywhere (and I guess you'd argue that I am not storing it in my example code - I am trying to grasp the problem, I would argue that reading from an object should not contain write operations in the first place, and that's what this error suggests is happening, I believe).
— Reply to this email directly, view it on GitHub https://github.com/cweiske/jsonmapper/issues/216#issuecomment-1812777693, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACBHPTJFG6D2ZXHE4BZGOWLYETPNVAVCNFSM6AAAAAA7MPNJZGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMJSG43TONRZGM . You are receiving this because you authored the thread.Message ID: @.***>
Oh, yeah, now I remembered why I was using JSON - because it is possible to query it directly in the DB. Unfortunately, using serialize does not allow for that. But I might need to duplicate serialized data as another column to achieve what I am trying to do.