Closed
Description
When bStrictObjectTypeChecking
is false
, a property of type object
might have its constructor invoked with the value provided by the JSON if it wasn't compatible, which is useful for hydrating stuff like DateTime
.
However, the code does not check for the following error conditions:
- Whether the class actually has a constructor (otherwise the argument won't be handled)
- Whether the constructor has >0 accepted arguments (otherwise the argument won't be handled)
- Whether the constructor requires no more than 1 argument (otherwise it will crash)
- Whether the constructor accepts the type of argument given without bailing out
- Whether the class is actually a JsonMapper model with
@required
properties which won't be set by invoking the constructor (violating expectations of user code)
An example of the last case in particular that bit me on the ass:
ClientData.php:
<?php
declare(strict_types=1);
/**
* Model class for LoginPacket JSON data for JsonMapper
*/
final class ClientData{
/**
* @var ClientDataPersonaSkinPiece[]
* @required
*/
public array $PersonaPieces;
}
ClientDataPersonaSkinPiece.php:
<?php
declare(strict_types=1);
/**
* Model class for LoginPacket JSON data for JsonMapper
*/
final class ClientDataPersonaSkinPiece{
/** @required */
public string $PieceId;
/** @required */
public string $PieceType;
/** @required */
public string $PackId;
/** @required */
public bool $IsDefault;
/** @required */
public string $ProductId;
}
When used in the following manner:
$mapper = new JsonMapper();
$mapper->bExceptionOnMissingData = true;
$mapper->map(json_decode('{"PersonaPieces":["test"]}'), new ClientData());
results in the following unexpected output:
object(ClientData)#6 (1) {
["PersonaPieces"]=>
array(1) {
[0]=>
object(ClientDataPersonaSkinPiece)#9 (0) {
["PieceId"]=>
uninitialized(string)
["PieceType"]=>
uninitialized(string)
["PackId"]=>
uninitialized(string)
["IsDefault"]=>
uninitialized(bool)
["ProductId"]=>
uninitialized(string)
}
}
}
Metadata
Metadata
Assignees
Labels
No labels