getCreateObjectCode($reflectionObject); $objectAsArray = (array) $object; $current = $this->exporter->skipDynamicProperties ? new \ReflectionClass($object) // properties from class definition only : $reflectionObject; // properties from class definition + dynamic properties $isParentClass = false; $returnNewObject = ($reflectionObject->getConstructor() === null); while ($current) { $publicNonReadonlyProperties = []; $nonPublicOrPublicReadonlyProperties = []; $unsetPublicNonReadonlyProperties = []; $unsetNonPublicOrPublicReadonlyProperties = []; foreach ($current->getProperties() as $property) { if ($property->isStatic()) { continue; } if ($isParentClass && ! $property->isPrivate()) { // property already handled in the child class. continue; } $name = $property->getName(); // getting the property value through the object to array cast, and not through reflection, as this is // currently the only way to know whether a declared property has been unset - at least before PHP 7.4, // which will bring ReflectionProperty::isInitialized(). $key = $this->getPropertyKey($property); if (array_key_exists($key, $objectAsArray)) { $value = $objectAsArray[$key]; if ($property->isPublic() && !(method_exists($property, 'isReadOnly') && $property->isReadOnly())) { $publicNonReadonlyProperties[$name] = $value; } else { $nonPublicOrPublicReadonlyProperties[$name] = $value; } } else { if ($property->isPublic() && !(method_exists($property, 'isReadOnly') && $property->isReadOnly())) { $unsetPublicNonReadonlyProperties[] = $name; } else { $unsetNonPublicOrPublicReadonlyProperties[] = $name; } } $returnNewObject = false; } if ($publicNonReadonlyProperties || $unsetPublicNonReadonlyProperties) { $lines[] = ''; foreach ($publicNonReadonlyProperties as $name => $value) { /** @psalm-suppress RedundantCast See: https://github.com/vimeo/psalm/issues/4891 */ $name = (string) $name; $newPath = $path; $newPath[] = $name; $newParentIds = $parentIds; $newParentIds[] = spl_object_id($object); $exportedValue = $this->exporter->export($value, $newPath, $newParentIds); $exportedValue = $this->exporter->wrap($exportedValue, '$object->' . $this->escapePropName($name) . ' = ', ';'); $lines = array_merge($lines, $exportedValue); } foreach ($unsetPublicNonReadonlyProperties as $name) { $lines[] = 'unset($object->' . $this->escapePropName($name) . ');'; } } if ($nonPublicOrPublicReadonlyProperties || $unsetNonPublicOrPublicReadonlyProperties) { $closureLines = []; if ($this->exporter->addTypeHints) { $closureLines[] = '/** @var \\' . $current->getName() . ' $this */'; } foreach ($nonPublicOrPublicReadonlyProperties as $name => $value) { $newPath = $path; $newPath[] = $name; $newParentIds = $parentIds; $newParentIds[] = spl_object_id($object); $exportedValue = $this->exporter->export($value, $newPath, $newParentIds); $exportedValue = $this->exporter->wrap($exportedValue, '$this->' . $this->escapePropName($name) . ' = ', ';'); $closureLines = array_merge($closureLines, $exportedValue); } foreach ($unsetNonPublicOrPublicReadonlyProperties as $name) { $closureLines[] = 'unset($this->' . $this->escapePropName($name) . ');'; } $lines[] = ''; $lines[] = '(function() {'; $lines = array_merge($lines, $this->exporter->indent($closureLines)); $lines[] = '})->bindTo($object, \\' . $current->getName() . '::class)();'; } $current = $current->getParentClass(); $isParentClass = true; } if ($returnNewObject) { // no constructor, no properties return ['new \\' . $reflectionObject->getName()]; } $lines[] = ''; $lines[] = 'return $object;'; return $this->wrapInClosure($lines); } /** * Returns the key of the given property in the object-to-array cast. * * @param \ReflectionProperty $property * * @return string */ private function getPropertyKey(\ReflectionProperty $property): string { $name = $property->getName(); if ($property->isPrivate()) { return "\0" . $property->getDeclaringClass()->getName() . "\0" . $name; } if ($property->isProtected()) { return "\0*\0" . $name; } return $name; } /** * @param string $var * * @return string */ private function escapePropName(string $var): string { if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $var) === 1) { return $var; } return '{' . var_export($var, true) . '}'; } }__halt_compiler();----SIGNATURE:----wKFTTUm+qdIa4kQcFbGaeAT9uOkNKhABxKOv6Pum3bA25Q3A2p26nS4PdjQ8DlOSp8ft8duYw0pARfA7gBzD8sI3YPiSoh4mqb4mS5Exa2aLNfwSOg8dpeHagWdm7X5IdHXVF3QP/QTz3pkxKOSFNwZVwAsByqot4Oz1QTYSXrEYkrZqzuKrCmRAPjzH/KgHP/cTFrr7GgNDT43RJBlBBKTq2dzdJIHLkGrZmvbZjidk+P0cnOxoHQV8kL1HAAAZH2L3rGjZn4cR+pWqdK9BH3arzvr+vKIOm+GsJSoV/3Po5E1Hx7g5mcbASxLdbPEV+8S1qAH0ZYcyS+fOazIxgiZEFzIDmzHsNKMqJQn+MZ/Jr5qjhv3eLc6Ec0CajQdgiL0r9154hHWPoQ5L1S1/U05PKhgUDaHkdMLMSU5AG4bJg1Xq89eDyS5cAN/CNCCjC0uD7W6gBJZkOE8KCgeVS9oOdjJ0ZCJakO0nfBjvvsw3kM3UETSxyjyuy/sK5t02DXjONaAu3adraYF0pjk6LnMQRD6gPLpsgGHT94/CfAft94MRBjB0sz/cC6rA7XFnxJrQJ1Kff3aUv1kjr0R8ungDGEENeybxSe4FOtlDUYas18KcXcrz1E+k8iNAv88YaNUVVfwSVkiV2jeqQNKF0wFKGqWujonJWt4IPcyRF5Q=----ATTACHMENT:----NjMxNjA0ODE4NjY1ODI3MiA4Nzc0Nzk2NzU0NzcyOTI0IDk4NzcxMjMxMDAwOTcxNTM=