Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Object Enumerator Laravel Package

sebastian/object-enumerator

Traverses arrays and object graphs to enumerate every referenced object, including nested structures and circular references. A small utility from Sebastian Bergmann's PHP testing stack, commonly pulled in by PHPUnit to walk object graphs safely.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit — a utility, not a component. sebastian/object-enumerator is one final class with one cycle-safe method: enumerate() walks arrays and object graphs, reflects into non-public properties, dedupes by object identity, and returns a flat array of reachable objects. There is no service provider, no config, no facade, no Laravel coupling. That makes it perfectly compatible and almost entirely irrelevant to application architecture. Its true position in our dependency graph is as a transitive artifact: PHPUnit pulls it in via sebastian/comparator to find mocks and walk test arguments. The 6,527 stars and the Dependents: 0 figure should both be read correctly — the former reflects reflected glory from the PHPUnit ecosystem, the latter is a Packagist metadata artifact, not an adoption signal.

Integration feasibility — mechanically trivial, strategically thin. composer require --dev succeeds in seconds and resolves to a version we already have. So the TPM question is never "can we install this," it's "is there a named caller?" Value is only realized at a direct call site, and in a Laravel codebase that means exactly two shapes: custom test assertions (graph-shape, retained-reference, leak checks) or an internal, non-production inspector command. Absent one of those, this is capability inventory, not a project. The 42.3 score and 56.2 opportunity score corroborate that read: high utility, low leverage — infrastructure to consume, not an investment to champion.

Technical risk — low at runtime, moderate at the version boundary. Three items belong on the risk register before this becomes a decision:

  1. Ambiguous PHP floor. Release notes for 8.0.0 and 7.0.0 read "no longer supported on PHP 8.3" / "PHP 8.2." Across the sebastian/* family this phrasing conventionally signals a minimum-version bump, but it is genuinely ambiguous in this text. Do not plan a PHP upgrade on either interpretation — verify against the installed require constraint in composer.json first. This is a one-command check and a hard gate.
  2. Constraint duplication. Declaring the dependency directly creates a second constraint set that can collide with PHPUnit's own during a PHPUnit major bump. Mitigation is version-following discipline, covered in the integration section.
  3. Unbounded traversal. Depth-first with no depth cap, no predicate, no result limit. A fully hydrated Eloquent aggregate or a large service container will be slow and memory-hungry. This is the single realistic incident vector.

Behavioral note: 8.1.0 fixed infinite recursion on self-referencing arrays and materially improved large-graph performance. Anything pinned below that inherits a known flakiness class.

Key questions

  • Who is the named caller — a specific assertion helper, leak check, or internal inspector — and what does it replace? If we cannot answer this in one sentence, the answer is "defer."
  • What version does composer show sebastian/object-enumerator already report, and which PHPUnit major is resolving it?
  • Which PHP versions are in our CI matrix, and does the installed constraint cover the maximum?
  • Do we need identity-level, cycle-safe traversal that Arr:: helpers, json_encode, or Symfony VarDumper genuinely cannot provide? (Usually the answer is no; when it's yes, it's decisive.)
  • Who owns the wrapper, and does it live under tests/ or app/? The answer must be tests/ unless a non-production-only guard exists.
  • Are we prepared to keep this permanently dev-only, with zero production call sites? If not, stop now — this package has no business in a request path.

Integration Approach

Stack fit — dev-only, deliberately. require-dev, consumed from a test helper trait or a local/CI-gated artisan command. It should never appear in a production code path. Be explicit with stakeholders about what it is not: not a replacement for dump()/VarDumper (which produces human output), not a deep-clone or serialization mechanism (native or dedicated serializers), not an ORM or container introspection substitute. Teams routinely reach for graph enumeration expecting value comparison or deep-copy semantics and get burned; write that line down.

Migration path — inventory before install. There is no migration, only a two-step promotion. Step one is an audit, not a change: confirm transitive presence and record the resolved version from composer.lock. Step two, triggered only by a direct call site, is promoting it to an explicit require-dev entry. Promotion is worth doing at that point because it converts an implicit dependency into a declared one and protects us if PHPUnit restructures its tree — but doing it speculatively just buys us a constraint we have to maintain.

Compatibility

  • PHP: governed entirely by the installed version's require constraint. Verify per CI matrix entry; re-verify on every PHP minor and major upgrade. This is the recurring tax, and it is small but non-zero.
  • PHPUnit/Pest: let the test framework drive the version. Declare phpunit/phpunit loosely, pin this package to whatever PHPUnit already resolves, and never pin it independently. Independent pinning is the only way to manufacture a conflict here.
  • Laravel: zero coupling. Laravel 10/11/12 is irrelevant. This is a genuine plus — zero framework-upgrade tax, which is rare enough to be worth naming in the decision record.

Sequencing

  1. Inventory. Confirm transitive presence and current version.
  2. Demand validation — the real gate. Name the concrete use case and document why the alternatives (VarDumper, spl_object_id set comparison, Arr:: helpers, assertSame on identity) are insufficient. If step 2 is unconvincing, stop here and record the outcome. Most teams should stop here.
  3. Wrap, don't spray. If justified, ship one Tests\Support\ObjectGraphAssertions trait or a Support\ObjectGraph helper with intent-named methods (assertGraphHasOnly, assertNoLeakedObjects). Wrap before first use, not after. The API is one method today, but the wrapper is our exit ramp and our documentation, because upstream offers only a README and release notes.
  4. Declare require-dev at the version PHPUnit already resolves; add CI coverage at our minimum and maximum PHP versions.
  5. Document in one short internal note. The wrapper docblock is the documentation. There is no vendor doc site to lean on.

Deliverable framing for planning: steps 1–2 are an afternoon of engineering judgment; steps 3–5 are one to two days including review. Size accordingly and do not open a multi-sprint epic.

Operational Impact

Maintenance — near-zero for the package itself. It is a leaf utility released in lockstep with PHPUnit majors, and we inherit PHPUnit's testing of it as a downstream consumer. The residual cost is ours and is confined to two things: the wrapper, and a small review task at each PHPUnit major bump confirming the transitive version still satisfies both our constraint and our PHP floor. Budget effectively zero ongoing effort; call it an hour per test-framework major.

Support — no first-party channel, no SLA, effectively a single maintainer. That is acceptable precisely because we never depend on it in production, and because PHPUnit exercises it heavily upstream — it is crowd-tested by the ecosystem at large. The wrapper converts any upstream behavioral shift from an investigation into a one-file change. I would not sign off on this dependency for a production path; for tests/, the support profile is fine.

Scaling — negligible for ordinary suites, with two identifiable cliffs. Graph size: a fully hydrated Eloquent aggregate or a thousand-entry service container will burn time and memory, and lazy-loaded proxies and "ghost" models will silently inflate what gets enumerated. Call frequency: per-assertion enumeration across a large suite multiplies the cost invisibly. Mitigations are scope-limiting the input before enumeration, keeping calls out of hot loops, and — because the failure looks like random CI flakiness rather than a graph problem — having the wrapper name its call site in any error path.

Failure modes

  • Version conflict on a PHPUnit major if we pinned independently — surfaces as a composer resolution failure: loud, early, benign.
  • PHP/constraint mismatch — install failure in the good case; a runtime error on a newer CI image that passes locally in the bad one. This is the failure mode most likely to cost real team hours, which is why the PHP-floor check is a gate, not a footnote.
  • OOM or timeout on large graphs — presents as intermittent CI flake and consumes debugging time disproportionate to the benefit. Mitigated by wrapper-level input scoping.
  • Circular references — explicitly handled upstream; that is the package's reason to exist, not a risk. The risk is uncapped depth, not cycles.
  • Semantic misreading — it enumerates referenced objects, not values. Teams expecting deep-copy or value-comparison semantics, or surprised by lazy-loaded relations, will draw wrong conclusions and ship bad assertions. One line in the internal note.
  • Tool confusion — developers reaching for this when dump() would have answered the question in five seconds. Reinforce in the note; this is the most likely actual cost of adoption.

Ramp-up — trivial: one class, one method, roughly fifteen minutes for a PHP-fluent developer. Skip formal training entirely. The real cost is discoverability, since there is nothing beyond a README; recommend a single 30-minute pairing session when the first real use case lands, and budget it against that use case rather than as general enablement.

TPM recommendation: Do not adopt as a direct dependency now. Record it as a pre-approved, already-installed, dev-only capability gated on a named caller in test tooling or internal inspection. Revisit only if we commit to custom graph assertions or an object-graph inspector — at which point the wrapper (step 3) is the deliverable and the dependency is a formality. Success metric is not adoption; it's whether we ever needed to write custom recursive traversal code. If we didn't, this package did its job from vendor/ without us.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package