PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

Cloning a Singleton is not allowed!

Error message

Cloning a Singleton is not allowed!

What it means

ReferenceHelper is a singleton obtained via ReferenceHelper::getInstance(); its __clone is declared final and unconditionally throws, enforcing the singleton contract at the language level. The library does this so no second helper instance can drift out of sync with the one wired into the spreadsheet's insert/delete machinery.

Source

Thrown at src/PhpSpreadsheet/ReferenceHelper.php:1409

            // Style
            $coordinate = Coordinate::stringFromColumnIndex($i) . ($beforeRow - 1);
            if ($worksheet->cellExists($coordinate)) {
                $xfIndex = $worksheet->getCell($coordinate)->getXfIndex();
                for ($j = $beforeRow; $j <= $beforeRow - 1 + $numberOfRows; ++$j) {
                    if (!empty($xfIndex) || $worksheet->cellExists([$i, $j])) {
                        $worksheet->getCell(Coordinate::stringFromColumnIndex($i) . $j)->setXfIndex($xfIndex);
                    }
                }
            }
        }
    }

    /**
     * __clone implementation. Cloning should not be allowed in a Singleton!
     */
    final public function __clone()
    {
        throw new Exception('Cloning a Singleton is not allowed!');
    }
}

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Drop the clone and call ReferenceHelper::getInstance() wherever the helper is needed; it always returns the same shared instance
  2. If you need an independent copy of document state, copy the Spreadsheet (copy() / duplicate sheets), not the helper
  3. In generic deep-clone walkers, skip singletons or objects whose __clone throws

Example fix

// before
$helper = ReferenceHelper::getInstance();
$copy = clone $helper; // throws: Cloning a Singleton is not allowed!

// after
$helper = ReferenceHelper::getInstance(); // reuse the shared instance
Defensive patterns

Strategy: validation

Validate before calling

// Refuse to clone known singletons before a generic deep-clone walk
function safeClone(mixed $obj): mixed
{
    if ($obj instanceof \PhpOffice\PhpSpreadsheet\ReferenceHelper) {
        return \PhpOffice\PhpSpreadsheet\ReferenceHelper::getInstance();
    }

    return clone $obj;
}

Type guard

function isCloneableService(object $obj): bool
{
    return !($obj instanceof \PhpOffice\PhpSpreadsheet\ReferenceHelper);
}

Prevention

When it happens

Trigger: Any direct clone of the singleton: $helper = ReferenceHelper::getInstance(); $copy = clone $helper; generic deep-clone utilities that blindly clone every object in a graph; prototype-style code applied to services it did not create.

Common situations: Copy/pasted 'deep clone' helpers that iterate object properties and clone everything; attempts to snapshot spreadsheet state by cloning internals; frameworks that clone services during container compilation.

Related errors


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/8749a4b461ac395a. Report an issue: GitHub.