manychois / composery
A strongly-typed PHP library providing a low-level API equivalent to the Composer CLI
Requires
- php: >=8.5
Requires (Dev)
- phpstan/extension-installer: ^1.4.3
- phpstan/phpstan: ^2.1.46
- phpstan/phpstan-phpunit: ^2.0.16
- phpstan/phpstan-strict-rules: ^2.0.10
- phpunit/phpunit: ^12.5.15 || ^13.0.0
- slevomat/coding-standard: ^8.22.1
- squizlabs/php_codesniffer: ^3.13.5
README
A strongly-typed PHP library providing a low-level API equivalent to the Composer CLI.
Each Composer command maps to a corresponding method on the Composer class. All
methods come in two variants: blocking (returns a ComposerResult) and
streaming (returns a Generator that yields OutputLine objects as they arrive).
Requirements
- PHP 8.5 or later
- Composer binary accessible on the system (or bundled — see below)
Installation
composer require manychois/composery
Bundled Composer binary
The test suite ships with a bundled Composer binary at
tests/Integration/composer (version 2.9.5,
SHA-256 c86ce603fe836bf0861a38c93ac566c8f1e69ac44b2445d9b7a6a17ea2e9972a).
This binary is used exclusively during integration tests and is not installed as
a production dependency.
Quick start
use Manychois\Composery\Composer; use Manychois\Composery\Environment; $env = new Environment(workingDir: '/path/to/your/project'); $composer = new Composer($env); // Blocking — waits until the command finishes $result = $composer->install(); if ($result->successful()) { echo "Installed in {$result->duration()}s\n"; } else { echo "Failed (exit {$result->exitCode()}):\n{$result->output()}"; }
Streaming output in real time
use Manychois\Composery\Composer; use Manychois\Composery\Command\UpdateOptions; use Manychois\Composery\Environment; use Manychois\Composery\Runner\OutputSource; $env = new Environment(workingDir: '/path/to/your/project'); $composer = new Composer($env); $options = new UpdateOptions(); $options->noDev = true; $gen = $composer->updateStreaming(options: $options); foreach ($gen as $line) { $prefix = $line->source === OutputSource::Stderr ? '[err] ' : ''; echo $prefix . $line->content . "\n"; } $result = $gen->getReturn(); echo "Exit code: {$result->exitCode()}\n";
Environment configuration
Environment controls the working directory, COMPOSER_HOME, the PHP
memory limit, and an optional explicit path to the Composer binary.
use Manychois\Composery\Environment; $env = new Environment( workingDir: '/var/www/app', composerHome: '/tmp/composer-home', // default memoryLimit: '1G', // default: 512M binaryPath: '/usr/local/bin/composer', // null = auto-detect );
Binary resolution order
When binaryPath is null, BinaryLocator searches in this order:
binaryPathfromEnvironment(if set)$COMPOSER_HOME/composeror$COMPOSER_HOME/composer.pharwhich composer(Unix) /where composer(Windows)composer.pharinworkingDir
Throws ComposerNotFoundException if nothing is found.
Global options
Every options class extends AbstractGlobalOption, which exposes the following
flags available to all commands:
| Property | CLI flag | Default |
|---|---|---|
$help |
--help / -h |
false |
$noCache |
--no-cache |
false |
$noPlugins |
--no-plugins |
false |
$noScripts |
--no-scripts |
false |
$profile |
--profile |
false |
$quiet |
--quiet / -q |
false |
$verbose |
--verbose / -v |
false |
$version |
--version / -V |
false |
$workingDir |
--working-dir= / -d |
null |
--no-interaction and --no-ansi are always injected by the runner and are
not exposed as options.
API reference
Composer is constructed with an Environment and an optional BinaryLocator:
new Composer(Environment $environment, ?BinaryLocator $locator = null)
Every command is available in a blocking variant that returns ComposerResult and a
streaming variant that returns a Generator<int, OutputLine, null, ComposerResult>.
Options classes carry the same name as the method with an Options suffix
(e.g. install → InstallOptions). All options classes extend AbstractGlobalOption;
see the global options table above for the inherited flags.
| Blocking method | Streaming method | Composer docs |
|---|---|---|
init |
initStreaming |
init |
install |
installStreaming |
install |
update |
updateStreaming |
update |
require |
requireStreaming |
require |
remove |
removeStreaming |
remove |
dumpAutoload |
dumpAutoloadStreaming |
dump-autoload |
validate |
validateStreaming |
validate |
show |
showStreaming |
show |
outdated |
outdatedStreaming |
outdated |
checkPlatformReqs |
checkPlatformReqsStreaming |
check-platform-reqs |
composer.json as a typed model (Schema\Project)
The Manychois\Composery\Schema namespace provides value objects that mirror the
composer.json schema. The root type
is Project: a mutable, strongly-typed representation of a manifest after you
decode the file to a PHP array.
use Manychois\Composery\Schema\Project; $path = '/path/to/your/project/composer.json'; $json = \json_decode((string) \file_get_contents($path), true); \assert(\is_array($json)); $project = Project::parse($json); echo $project->name ?? '(unnamed)'; print_r($project->require);
Project::parse() walks the associative array and fills public properties. Known
nested structures become dedicated classes (for example Author, Support,
Autoload, AutoloadDev, Scripts, ProjectConfig, Archive, PhpExt,
Source, Dist, and Funding). String-key dependency maps (require,
require-dev, replace, conflict, provide, suggest) stay as
array<string, string>. minimum-stability is parsed into the
MinimumStability enum when present. The repositories field is a
list<mixed> because entries can be objects or shorthand strings.
Project implements JsonSerializable. Calling json_encode($project) emits a
shape suitable for persisting back to JSON (only non-empty / non-null fields are
included, matching typical composer.json usage).
This layer is separate from the Composer runner: it does not invoke Composer or
read files by itself. Use it whenever your application needs to inspect or build
manifest data with IDE and PHPStan-friendly types instead of raw arrays.
Return types
ComposerResult
| Method | Return type | Description |
|---|---|---|
successful() |
bool |
true when exit code is 0 |
exitCode() |
int |
Raw process exit code |
output() |
string |
Combined stdout + stderr output |
duration() |
float |
Wall-clock time in seconds |
OutputLine (streaming)
| Property | Type | Description |
|---|---|---|
$content |
string |
The line text (newline stripped) |
$source |
OutputSource |
OutputSource::Stdout or OutputSource::Stderr |
$timestamp |
float |
microtime(true) when the line was captured |
The generator's return value (available via $gen->getReturn() after the loop)
is the ComposerResult for the completed command.
Enums
PreferMode
| Case | CLI flag |
|---|---|
PreferMode::Dist |
--prefer-dist |
PreferMode::Source |
--prefer-source |
PreferMode::None |
(no flag emitted) |
ListFormat
| Case | CLI value |
|---|---|
ListFormat::Text |
(default, no flag emitted) |
ListFormat::Json |
--format=json |
Exceptions
| Class | Thrown when |
|---|---|
ComposerNotFoundException |
No Composer binary can be located |
ComposerRunFailedException |
(reserved for future use) |