rector/rector-phpoffice
Rector rules for PhpOffice libraries that automate upgrading PhpSpreadsheet, PhpWord, and related packages. It applies safe, version-aware code transformations so you can modernize legacy PhpOffice code with less manual work and fewer regressions.
Architecture fit. rector/rector-phpoffice is not a library — it is a ruleset that plugs into Rector's AST engine to mechanically rewrite PHPExcel calls into PhpSpreadsheet equivalents. That means it should be treated as a one-shot migration utility pinned to a dev dependency, never as a runtime or platform component. Architecturally this is favorable: it introduces zero coupling into shipped code, produces reviewable diffs, and can be deleted from composer.json the day after the migration closes. It also composes cleanly with the rest of the Rector ecosystem (Laravel sets, PHP version sets, phpunit sets) already likely present in a Laravel codebase.
Integration feasibility. High for the mechanical subset, low for everything that matters. Rector rules reliably handle namespace changes (PHPExcel_* → PhpSpreadsheet\*), class renames, and some method renames. They cannot handle the semantic divergence between the two libraries — date/time handling, cell value binding, style cloning, formula calculation, and reader/writer option changes all behave differently and produce valid but wrong code. Expect the ruleset to eliminate perhaps 40–60% of the rote work and 0% of the hard work.
Technical risk. Three concrete concerns, in order:
composer.json will constrain you to a specific Rector major, which may conflict with the version your other Rector sets require.Key questions for the team.
.xlsx output byte-for-byte or cell-for-cell?Stack fit. Native fit for a Laravel/PHP monolith on Composer. The ruleset lives in a dedicated config file (e.g., rector-phpoffice.php) so it can be invoked selectively rather than as part of the default refactor pipeline — important, because you do not want a one-time migration running on every PR forever. PHPExcel and PhpSpreadsheet are separate Composer packages with distinct namespaces, so both can coexist in composer.json during the transition, which is the single most valuable property here: it enables incremental, module-by-module migration rather than a big-bang cutover.
Migration path.
Compatibility. Verify three pins before committing: PHP version range, Rector major version, and PhpSpreadsheet target major. Any mismatch should push you toward forking the rules into the repo and adjusting them, which is cheap — the rule classes are small and the transformation logic is well understood.
Sequencing. Treat this as a bounded modernization workstream, not an infrastructure initiative. It should be scheduled against a business driver — typically PHP version upgrade or a security/compliance requirement to drop the abandoned PHPExcel package — and given a fixed time box. If the driver is absent, defer; there is no ongoing value in adopting this package.
Maintenance. Effectively fork-and-own. Budget for the ruleset to be vendored into an internal tools/ directory with a named owner and a documented "delete after migration completes" note. Upstream maintenance should be assumed to be zero — a single-maintainer, unstarred project has no support SLA and no obligation to fix edge cases your codebase surfaces.
Support and ramp-up. No vendor support, no documentation beyond the README. Ramp-up for an engineer already comfortable with Rector is roughly one day; for a team unfamiliar with AST-based refactoring, add a half-day of pairing plus a written review protocol. The real ramp-up cost is not learning the tool — it is building the confidence that the generated diffs are correct. That cost lives in the regression harness, not in the ruleset.
Scaling. Runtime is irrelevant; this never ships. CI cost is the scaling axis: Rector on a large monolith can take many minutes, and running it repo-wide on every PR is wasteful. Scope invocation to changed paths or to scheduled/manual runs. The other scaling axis is rule count — as you add the Rector Laravel sets alongside this one, version conflicts between rulesets become a real operational tax.
Failure modes to instrument for.
| Failure | Symptom | Detection |
|---|---|---|
| Silent semantic drift | Exports produce subtly different dates, precision, or styles | Output-fixture comparison; not caught by type checks |
| Partial migration | Rules skip unfamiliar call patterns | Post-run grep for PHPExcel and PHPExcel_ across the tree |
| Abandoned upstream | Edge case blocks progress with no fix path | Mitigated by vendoring the rules internally |
| Rector version conflict | Cannot upgrade core Rector | Pin and test in isolation before merging configs |
| Dual-library drift | New code written against PHPExcel after migration starts | Lint rule / CI check blocking new PHPExcel imports |
Recommendation. Adopt as a time-boxed accelerator inside a migration project, not as a dependency. Fork the rules into the repository, enforce a CI guard that forbids new PHPExcel usage, require output-fixture tests before any automated rewrite is merged, and define "done" as PHPExcel removal from composer.json plus a clean grep. The low opportunity score is a fair signal: the package saves real hours on mechanical renames, but the risk-adjusted value is entirely contingent on the team already having a spreadsheet regression harness — without one, the automated diffs are unverifiable and the tool should not be used.
How can I help you explore Laravel packages today?