Skip to content

Constructor arguments are not validated when constructing object types from flat types #226

Closed
@dktapps

Description

@dktapps

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

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions