nadar/php-composer-reader
A small PHP library for reading and manipulating composer.json files. Check readability and writability, retrieve metadata like description, and iterate over sections such as require and autoload to inspect packages, version constraints, and PSR mappings.
nadar/php-composer-reader is a plain PHP utility, not a Laravel package. There is no service provider or config file to publish; install it and use it directly where you need to inspect or rewrite composer.json.
composer require nadar/php-composer-reader
Start with the README and then look at vendor/nadar/php-composer-reader/src for the concrete section classes. The first practical use case is an internal Artisan command that audits dependencies or checks autoload mappings.
use Nadar\ComposerReader\ComposerReader;
use Nadar\ComposerReader\RequireSection;
$reader = new ComposerReader(base_path('composer.json'));
if (! $reader->canRead()) {
throw new RuntimeException('composer.json is not readable.');
}
foreach (new RequireSection($reader) as $package) {
dump($package->name, $package->constraint);
}
Only call canWrite() when you actually intend to save. For read-only audits, checking writability adds unnecessary failure modes, especially in production or read-only CI checkouts.
Dependency audit Artisan command. Wrap the reader in a small command rather than scattering it through controllers. Iterate RequireSection and RequireDevSection, compare constraints with greaterThan(), and output a table.
use Nadar\ComposerReader\ComposerReader;
use Nadar\ComposerReader\RequireSection;
use Nadar\ComposerReader\RequireDevSection;
$reader = new ComposerReader(base_path('composer.json'));
$rows = [];
foreach ([new RequireSection($reader), new RequireDevSection($reader)] as $section) {
foreach ($section as $package) {
$rows[] = [$package->name, $package->constraint];
}
}
$this->table(['Package', 'Constraint'], $rows);
Autoload mapping checks. Use AutoloadSection to inspect PSR-4 or PSR-0 mappings. This is useful for package scaffolds, migration scripts, and CI guardrails that detect stale or duplicate namespace mappings.
use Nadar\ComposerReader\AutoloadSection;
$section = new AutoloadSection($reader, AutoloadSection::TYPE_PSR4);
foreach ($section as $autoload) {
$this->line($autoload->namespace . ' => ' . $autoload->source);
}
Programmatic edits with a safety wrapper. The library supports adding/removing autoload and require entries and saving the file, but composer.json is critical project state. For day-to-day tooling, wrap mutations:
composer.json to a backup.canRead() and canWrite().add() / remove() / save().composer validate.composer dump-autoload if autoload changed, or update the lock file if dependencies changed.$new = new Autoload($reader, 'Foo\\Bar\\', 'src/foo/bar', AutoloadSection::TYPE_PSR4);
$section = new AutoloadSection($reader);
$section->add($new)->save();
Use array input for tests and generators. Release 2.1.0 added array input support, which is valuable for in-memory manipulation, synthetic composer.json fixtures, and tests that should not touch disk. Treat any array input as schema-sensitive: nested require, autoload, and extra structures must match Composer’s schema. For production file edits, prefer the file-backed reader so read/write checks and save behavior remain explicit.
Use command helpers carefully. runCommand('dump-autoload') is convenient in local tooling, but it depends on a globally installed composer binary. In Laravel deployments, Composer may be absent or available only through a project-specific path. Prefer a Symfony Process call with an explicit binary path for CI and deploy scripts, and avoid running Composer commands from web requests.
Laravel integration. There is no facade, so create a thin application service or bind a factory:
$this->app->bind(ComposerReader::class, fn () => new ComposerReader(base_path('composer.json')));
Use a transient binding if the reader may be mutated. A singleton can accidentally carry changed state between jobs or tests.
Testing pattern. Copy a fixture composer.json into a temporary directory, run assertions against section readers, and delete the temp file. For pure read logic, array input from 2.1.0 is faster and avoids filesystem permissions. Keep composer validate in CI to catch malformed edits that unit tests miss.
composer.json is not the same as updating the project. Adding a requirement does not update composer.lock. Run composer update <package> or the appropriate lock-file update after dependency changes. dump-autoload only regenerates the autoloader.greaterThan() is not a full Composer semver solver. It is useful for simple checks, but constraints can contain ranges, ||, dev-*, platform packages, and aliases. Use composer/semver when you need real constraint resolution or intersection logic.require-dev, autoload-dev, or PSR mappings. Handle empty section iterators and missing keys rather than assuming structure.autoload is not always PSR-4. It can contain files, classmap, and PSR-0 entries. Use AutoloadSection::TYPE_PSR4 only when you specifically mean PSR-4.canWrite() can pass while the directory, ACLs, or filesystem mount still block writes. Catch save failures, write atomically where possible, and never expose a write path in a public endpoint.runCommand() has environment assumptions. It expects a globally available Composer executable. In CI, containers, and Laravel Forge/Vapor-style deployments, that may not be true. Log stdout/stderr and check exit codes.composer/semver if maintenance becomes a concern.$reader->getContent() or $reader->contentSection('extra', null) before blaming the section class. That shows whether the issue is JSON shape, missing data, or section parsing.contentSection() and build your own small wrapper. Keep custom section readers thin and schema-tolerant.How can I help you explore Laravel packages today?