PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

Polynomial Best Fit not yet implemented

Error message

Polynomial Best Fit not yet implemented

What it means

Thrown unconditionally by PolynomialBestFit::__construct(): the class carries `protected bool $implemented = false;` (PolynomialBestFit.php:27) and nothing ever sets it true, so any attempt to construct a polynomial trend throws before regression starts. It is a deliberate 'this math is not trusted/finished' switch, not a runtime condition you can influence.

Source

Thrown at src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php:193

        $this->slope = $coefficients; //* @phpstan-ignore assign.propertyType (this whole class is a mess)

        $this->calculateGoodnessOfFit($x_sum, $y_sum, $xx_sum, $yy_sum, $xy_sum, 0, 0, 0);
        foreach ($this->xValues as $xKey => $xValue) {
            $this->yBestFitValues[$xKey] = $this->getValueOfYForX($xValue);
        }
    }

    /**
     * Define the regression and calculate the goodness of fit for a set of X and Y data values.
     *
     * @param int $order Order of Polynomial for this regression
     * @param float[] $yValues The set of Y-values for this regression
     * @param float[] $xValues The set of X-values for this regression
     */
    public function __construct(int $order, array $yValues, array $xValues = [])
    {
        if (!$this->implemented) {
            throw new SpreadsheetException('Polynomial Best Fit not yet implemented');
        }

        parent::__construct($yValues, $xValues);

        if (!$this->error) {
            if ($order < $this->valueCount) {
                $this->bestFitType .= '_' . $order;
                $this->order = $order;
                $this->polynomialRegression($order, $yValues, $xValues);
                if (($this->getGoodnessOfFit() < 0.0) || ($this->getGoodnessOfFit() > 1.0)) {
                    $this->error = true;
                }
            } else {
                $this->error = true;
            }
        }
    }
}

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Use a supported fit: TREND_LINEAR, TREND_LOGARITHMIC, TREND_EXPONENTIAL or TREND_POWER all construct working BestFit classes.
  2. Compute the polynomial least-squares fit externally — e.g. the markrogoysk/math-php library (Regression::leastSquares) or a small normal-equations solver — and feed coefficients/results into your sheet manually.
  3. Wrap the call in try/catch and degrade to a linear fit for the same data if polynomial fitting is optional polish rather than a requirement.
  4. Track upstream PhpSpreadsheet issues/PRs; if you fix the math locally, set $implemented accordingly via a subclass and contribute back.

Example fix

// before
$fit = \PhpOffice\PhpSpreadsheet\Shared\Trend\Trend::trend(
    \PhpOffice\PhpSpreadsheet\Shared\Trend\Trend::TREND_POLYNOMIAL, $yValues, $xValues
); // Polynomial Best Fit not yet implemented

// after
use Markrogoysk\MathPHP\Statistics\Regression;
$reg = Regression::leastSquares($xValues, $yValues); // polynomial fit outside PhpSpreadsheet
$r2 = $reg->r2(); $coeffs = $reg->getParameters();
// or fall back: Trend::trend(Trend::TREND_LINEAR, $yValues, $xValues)
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED_TRENDS = [
    \PhpOffice\PhpSpreadsheet\Shared\Trend\Trend::TREND_LINEAR,
    \PhpOffice\PhpSpreadsheet\Shared\Trend\Trend::TREND_LOGARITHMIC,
    \PhpOffice\PhpSpreadsheet\Shared\Trend\Trend::TREND_EXPONENTIAL,
    \PhpOffice\PhpSpreadsheet\Shared\Trend\Trend::TREND_POWER,
];
// TREND_POLYNOMIAL is intentionally excluded: PolynomialBestFit is not implemented.

Type guard

function supportedTrendType(string $type): ?string
{
    return in_array($type, ['linear', 'logarithmic', 'exponential', 'power'], true) ? $type : null;
}

Try / catch

try {
    $fit = Trend::trend($type, $yValues, $xValues);
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
    if (str_contains($e->getMessage(), 'not yet implemented')) {
        $fit = Trend::trend(Trend::TREND_LINEAR, $yValues, $xValues); // graceful degradation
    } else { throw $e; }
}

Prevention

When it happens

Trigger: Calling Trend::trend(Trend::TREND_POLYNOMIAL, $yValues, $xValues) (or instantiating new PolynomialBestFit($order, $yValues, $xValues) directly). Regardless of data quality, order, or array sizes, the !$this->implemented check fires on the first line of the constructor.

Common situations: Porting Excel trendline features (polynomial order 2-6 fits) to server-side generation; unit-tested code that assumed the TREND_POLYNOMIAL constant implied a working implementation; exploring Shared\Trend classes and assuming feature parity across trend types.

Related errors


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