Repository: symfony/symfony
File: src/Symfony/Component/Form/MissingDataHandler.php (PHP)

Code before:
    {
        $this->missingData = new \stdClass();
    }

    public function handle(FormInterface $form, mixed $data): mixed
    {
        $processedData = $this->handleMissingData($form, $data);

        return $processedData === $this->missingData ? $data : $processedData;
    }

    private function handleMissingData(FormInterface $form, mixed $data): mixed
    {
        try {
            if ($form->getConfig()->getType() instanceof ResolvedFormTypeInterface && $form->getConfig()->getType()->getInnerType() instanceof CheckboxType) {
                $falseValues = $form->getConfig()->getOption('false_values');

                if ($data === $this->missingData) {
                    return $falseValues[0];
                }

                if (\in_array($data, $falseValues)) {
                    return $data;
                }
            }
        } catch (\Error $error) {
            if ('Typed property Symfony\Component\Form\FormConfigBuilder::$type must not be accessed before initialization' === $error->getMessage()) {
                return $data;
            }

            throw $error;
        }

        if (null === $data || $this->missingData === $data) {
            $data = $form->getConfig()->getCompound() ? [] : $data;
        }

        if (\is_array($data)) {
            $children = $form->getConfig()->getCompound() ? $form->all() : [$form];

            foreach ($children as $child) {
                $value = $this->handleMissingData($child, \array_key_exists($child->getName(), $data) ? $data[$child->getName()] : $this->missingData);

                if ($this->missingData !== $value) {
                    $data[$child->getName()] = $value;
                }
            }

            return $data ?: $this->missingData;
        }


Review comment (suggestion):
Catching type errors here doesn't look like the right solution to me. We should investigate instead why the `$type` property in `FormConfigBuilder` isn't initialized at this point and fix that root issue instead.

Code after:
    public function __construct()
    {
        $this->missingData = new \stdClass();
    }

    public function handle(FormInterface $form, mixed $data): mixed
    {
        $processedData = $this->handleMissingData($form, $data);

        return $processedData === $this->missingData ? $data : $processedData;
    }

    private function handleMissingData(FormInterface $form, mixed $data): mixed
    {
        $config = $form->getConfig();
        $missingData = $this->missingData;
        $falseValues = $config->getOption('false_values', null);

        if (\is_array($falseValues)) {
            if ($data === $missingData) {
                return $falseValues[0] ?? null;
            }

            if (\in_array($data, $falseValues)) {
                return $data;
            }
        }

        if (null === $data || $missingData === $data) {
            $data = $config->getCompound() ? [] : $data;
        }

        if (\is_array($data)) {
            $children = $config->getCompound() ? $form->all() : [$form];

            foreach ($children as $child) {
                $name = $child->getName();
                $childData = $missingData;

                if (\array_key_exists($name, $data)) {
                    $childData = $data[$name];
                }

                $value = $this->handleMissingData($child, $childData);

                if ($missingData !== $value) {
                    $data[$name] = $value;
                }
            }

            return $data ?: $missingData;