private function unserializeObject($object, &$data, string $className = null) : array
    {
        $reflectionClass = new \ReflectionClass($className ? $className : $object);
        unset($data['@type']);

        // parent class
        $parent = $reflectionClass->getParentClass();
        if ($parent) {
            $this->unserializeObject($object, $data, $parent->getName());
        }

        foreach ($reflectionClass->getProperties() as $property) {
            $name = $property->getName();

            if (array_key_exists($name, $data)) {
                $currentValue = $data[$name];

                if (isset($data[$name]['@ref'])) {
                    $currentValue = $this->references[$data[$name]['@ref']];
                } elseif (isset($data[$name]['@type'])) {
                    $reflection = new \ReflectionClass($data[$name]['@type']);

                    $parent = $reflection;
                    $internal = false;

                    while ($parent !== false) {
                        $internal = $parent->isInternal() ? true : $internal;
                        $parent = $parent->getParentClass();
                    }

                    if ($internal) {
                        $currentData = $data[$name];
                        $currentType = $data[$name]['@type'];
                        unset($currentData['@type']);

                        $serialize = preg_replace(
                            '`^a:`',
                            'O:' . strlen($currentType) . ':"' . $currentType . '":',
                            serialize($currentData)
                        );
                        $currentValue = unserialize($serialize);
                    } else {
                        $currentValue = $reflection->newInstanceWithoutConstructor();
                        $this->unserializeObject($currentValue, $data[$name]);
                    }
                } elseif (is_array($currentValue)) {
                    $currentValue = [];
                    foreach ($data[$name] as $key => $value) {
                        if (isset($value['@type'])) {
                            $reflection = new \ReflectionClass($value['@type']);
                            $currentValue[$key] = $reflection->newInstanceWithoutConstructor();
                            $this->unserializeObject($currentValue[$key], $value);
                        } else {
                            $currentValue[$key] = $value;
                        }
                    }
                }

                $property->setAccessible(true);
                $property->setValue($object, $currentValue);

                unset($data[$name]);
            }
        }

        return $data;
    }