PHP Composer

Ninguém escreve tudo do zero. Precisa registrar o que acontece na loja num arquivo de log? Gerar PDF? Enviar e-mail? Alguém já escreveu, testou e publicou esse código. O Composer é o programa que baixa essas bibliotecas (os pacotes), as dependências delas, e liga tudo ao seu projeto com o autoload. Todo projeto PHP moderno começa com ele.

Você vai aprender
  • O que o Composer faz e o que é o Packagist.
  • A criar um projeto com composer init e ler o composer.json linha por linha.
  • A instalar um pacote com composer require e a entender versões como ^3.12.
  • Para que servem o composer.lock e a pasta vendor/.
  • A diferença entre composer install e composer update.
  • O autoload PSR-4 do seu próprio código, dump-autoload e os scripts.
O Composer não roda no editor do guia

O Composer baixa pacotes da internet, e o editor do guia roda o PHP dentro do navegador, sem acesso à rede. Por isso as sessões desta aula foram feitas no terminal da Ana (com o Composer 2.10 de verdade) e aparecem como saídas. Os "Experimente" desta página treinam o que dá para treinar no navegador: ler e escrever o composer.json. Para repetir os comandos, use o seu próprio computador (veja Instalar no Linux ou no Windows e macOS).


A ideia: lista de compras, nota fiscal e despensa

Pense na despensa da Ana. Ela escreve uma lista de compras ("arroz, de preferência da versão 5 kg ou maior"), vai ao mercado e volta com os produtos e a nota fiscal (marca, peso e lote exatos de cada item). Os produtos vão para a despensa. O Composer funciona igual:

Dia a diaComposer
A lista de compras, escrita por vocêcomposer.json: os pacotes que o projeto precisa e quais versões servem
O mercadoO Packagist (packagist.org), o catálogo público de pacotes PHP
A nota fiscal, com as versões exatascomposer.lock: as versões exatas instaladas (gerado pelo Composer)
A despensaA pasta vendor/, onde ficam os pacotes baixados
O arroz traz junto o saquinho de temperoAs dependências dos pacotes, instaladas automaticamente

Conferindo o Composer

O Composer é um programa de linha de comando (escrito em PHP). Na máquina da Ana ele já está instalado:

$ composer --version
Composer version 2.10.3 2026-08-27 13:34:23
PHP version 8.5.8 (/opt/php/bin/php)
Run the "diagnose" command to get more detailed diagnostics output.

A resposta mostra a versão do Composer e qual PHP ele está usando. Se aparecer composer: comando não encontrado, siga as instruções de instalação em getcomposer.org (no Debian e Ubuntu também existe o pacote composer, mas costuma ser mais antigo).


Criando o projeto: composer init

O composer init cria o composer.json. Sem opções, ele faz perguntas uma a uma. Aqui a Ana passa todas as respostas de uma vez e usa --no-interaction ("sem perguntas"):

$ mkdir -p lojinha && cd lojinha
$ composer init --name=ana/lojinha --description="A lojinha da Ana" --author="Ana Silva <ana@exemplo.com>" --type=project --license=MIT --autoload=src/ --no-interaction
Writing ./composer.json
Generating autoload files
Generated autoload files
PSR-4 autoloading configured. Use "namespace Ana\Lojinha;" in src/
Include the Composer autoloader with: require 'vendor/autoload.php';
--name=ana/lojinha
O nome do pacote, sempre no formato fornecedor/projeto, em minúsculas. O "fornecedor" (vendor) é você, a sua empresa ou o seu usuário do GitHub.
--description, --author, --license
Descrição, autora e licença (MIT é uma licença livre bem simples).
--type=project
É um projeto (um site, um sistema), e não uma biblioteca para outros usarem (library).
--autoload=src/
Configura o autoload PSR-4 para a pasta src/.
--no-interaction
Não pergunta nada; usa o que foi passado e os valores padrão.

As últimas linhas da saída já dão as duas dicas mais importantes: o namespace do seu código é Ana\Lojinha (veio do nome ana/lojinha), e cada programa deve começar com require 'vendor/autoload.php';. Veja o que foi criado:

$ find . -type f | sort
./composer.json
./vendor/autoload.php
./vendor/composer/autoload_classmap.php
./vendor/composer/autoload_namespaces.php
./vendor/composer/autoload_psr4.php
./vendor/composer/autoload_real.php
./vendor/composer/autoload_static.php
./vendor/composer/ClassLoader.php
./vendor/composer/LICENSE

Um composer.json, uma pasta src/ vazia e a pasta vendor/ com o autoloader (ainda sem nenhum pacote).


O composer.json linha por linha

$ cat composer.json
{
    "name": "ana/lojinha",
    "description": "A lojinha da Ana",
    "type": "project",
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "Ana\\Lojinha\\": "src/"
        }
    },
    "authors": [
        {
            "name": "Ana Silva",
            "email": "ana@exemplo.com"
        }
    ],
    "require": {}
}
ChaveO que é
"name"Nome do pacote, fornecedor/projeto. Obrigatório só para bibliotecas publicadas; em projetos, é identificação.
"description"Uma frase sobre o projeto.
"type"project (um sistema) ou library (o padrão: uma biblioteca).
"license"A licença do código.
"autoload" → "psr-4"A regra do autoload: o namespace Ana\Lojinha\ mora em src/. Em JSON, a barra invertida é escrita dobrada (\\).
"authors"Uma lista ([ ]) de autores, cada um um objeto ({ }) com nome e e-mail.
"require"A lista de compras: pacote → versões aceitas. Ainda vazia.

Outras chaves que você vai encontrar: "require-dev" (pacotes só para desenvolvimento, como o PHPUnit), "scripts" (comandos com nome, logo abaixo), "config" (configurações do Composer) e "minimum-stability" (aceitar ou não versões de teste). O arquivo é JSON puro: aspas duplas sempre, sem vírgula depois do último item, sem comentários.

Missão: este pequeno programa lê o composer.json como o Composer faria e lista as dependências. Abra a aba composer.json e acrescente, em "require", o pacote "psr/log" na versão "^3.0". Cuidado com a vírgula entre os itens. A saída deve mostrar psr/log (^3.0).

<?php
$texto = file_get_contents(__DIR__ . '/composer.json');

if (!json_validate($texto)) {
    echo "composer.json inválido: ", json_last_error_msg(), "\n";
    exit(1);
}

$composer = json_decode($texto, true);
echo "Projeto: {$composer['name']}\n";
echo "Dependências:\n";
foreach ($composer['require'] ?? [] as $pacote => $versao) {
    echo "  - $pacote ($versao)\n";
}
foreach ($composer['autoload']['psr-4'] ?? [] as $prefixo => $pasta) {
    echo "Autoload: $prefixo -> $pasta\n";
}
{
    "name": "ana/lojinha",
    "type": "project",
    "autoload": {
        "psr-4": {
            "Ana\\Lojinha\\": "src/"
        }
    },
    "require": {
        "monolog/monolog": "^3.12"
    }
}
{
    "name": "ana/lojinha",
    "type": "project",
    "autoload": {
        "psr-4": {
            "Ana\\Lojinha\\": "src/"
        }
    },
    "require": {
        "monolog/monolog": "^3.12",
        "psr/log": "^3.0"
    }
}

Instalando um pacote: composer require

A Ana quer registrar os pedidos da loja num log (um diário de eventos do sistema). O pacote mais usado para isso é o Monolog, cujo nome no Packagist é monolog/monolog:

$ composer require monolog/monolog
./composer.json has been updated
Running composer update monolog/monolog
Loading composer repositories with package information
Updating dependencies
Lock file operations: 2 installs, 0 updates, 0 removals
  - Locking monolog/monolog (3.12.1)
  - Locking psr/log (3.0.2)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Downloading psr/log (3.0.2)
  - Downloading monolog/monolog (3.12.1)
  - Installing psr/log (3.0.2): Extracting archive
  - Installing monolog/monolog (3.12.1): Extracting archive
11 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.
Using version ^3.12 for monolog/monolog

(Algumas barras de progresso foram tiradas da saída.) Lendo de cima para baixo:

  1. composer.json has been updated: o pacote entrou na lista de compras.
  2. Loading composer repositories: o Composer consultou o Packagist.
  3. Lock file operations: 2 installs: pediu um pacote, vieram dois. O psr/log é uma dependência do Monolog, instalada automaticamente. Locking = "anotando na nota fiscal" a versão exata (3.12.1 e 3.0.2).
  4. Writing lock file: criou o composer.lock.
  5. Downloading / Installing: baixou e descompactou os pacotes em vendor/.
  6. suggestions, funding: avisos informativos (pacotes opcionais que o Monolog sabe usar; autores que aceitam doações). Pode ignorar.
  7. No security vulnerability advisories found: o Composer conferiu se alguma versão instalada tem falha de segurança conhecida. Nenhuma.
  8. Using version ^3.12: como a Ana não disse a versão, ele escolheu ^3.12 e escreveu no composer.json.
$ cat composer.json
{
    "name": "ana/lojinha",
    …
    "require": {
        "monolog/monolog": "^3.12"
    }
}
$ ls vendor
autoload.php
composer
monolog          « o pacote pedido
psr              « a dependência dele
$ du -sh vendor
1004K	vendor

O que quer dizer ^3.12

Os pacotes usam versionamento semântico: MAIOR.MENOR.CORREÇÃO. Em 3.12.1, o 3 só muda quando algo deixa de ser compatível; o 12 muda quando aparecem recursos novos; o 1, quando corrigem erros. O ^ (circunflexo) quer dizer "esta versão ou qualquer uma mais nova que não quebre o meu código":

RestriçãoAceitaUso
^3.123.12.0 até antes de 4.0.0O padrão e o recomendado
~3.12.13.12.1 até antes de 3.13.0Só correções, sem recursos novos
3.12.1Exatamente essaRaro; trava o pacote
>=3.0 <3.5Um intervaloCasos especiais
^2.0 || ^3.0A série 2 ou a série 3Bibliotecas que suportam as duas (o Monolog pede assim o psr/log)
*Qualquer umaEvite: a próxima versão maior pode quebrar tudo

Para escolher a versão na hora de instalar: composer require monolog/monolog:^3.0.


Usando o pacote

A Ana cria a sua primeira classe, no namespace que o composer init sugeriu:

<?php

declare(strict_types=1);

namespace Ana\Lojinha;

use Psr\Log\LoggerInterface;

class Pedido
{
    public function __construct(private LoggerInterface $log) {}

    public function fechar(string $cliente, float $total): void
    {
        $this->log->info("Pedido fechado", ['cliente' => $cliente, 'total' => $total]);
    }
}
<?php

declare(strict_types=1);

require __DIR__ . '/vendor/autoload.php';

use Ana\Lojinha\Pedido;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$log = new Logger('loja');
$log->pushHandler(new StreamHandler('php://stdout'));

$pedido = new Pedido($log);
$pedido->fechar('Bruno', 69.8);
$log->warning('Estoque baixo', ['produto' => 'Caneca', 'restam' => 2]);
require __DIR__ . '/vendor/autoload.php';
O único require. A partir dele, as classes do Monolog, do psr/log e as suas (Ana\Lojinha\…) carregam sozinhas.
use Monolog\Logger;
As classes do pacote têm namespace próprio (veja Namespaces). A documentação do pacote diz quais usar.
new Logger('loja')
Cria o "diário", com o nome loja.
pushHandler(new StreamHandler('php://stdout'))
Diz onde escrever: aqui, na saída do terminal. Num site, seria um arquivo, como __DIR__ . '/logs/loja.log'.
LoggerInterface
O Pedido não depende do Monolog, e sim da interface padrão de logs (PSR-3, do pacote psr/log). Qualquer biblioteca de log compatível serviria. Veja Padrões PSR.
$ php index.php
[2026-10-16T23:48:58.786901+00:00] loja.INFO: Pedido fechado {"cliente":"Bruno","total":69.8} []
[2026-10-16T23:48:58.788077+00:00] loja.WARNING: Estoque baixo {"produto":"Caneca","restam":2} []

Cada linha tem a data e hora, o nome do log, o nível (INFO, WARNING), a mensagem e os dados extras em JSON. Repare no +00:00: o horário está em UTC (no relógio da Ana eram 20:48), porque o PHP da Ana não tem fuso horário configurado. Veja Datas e Horas para ajustar o date.timezone.

Vendo o que está instalado

$ composer show
monolog/monolog 3.12.1 Sends your logs to files, sockets, inboxes, database...
psr/log         3.0.2  Common interface for logging libraries
$ composer show --tree
monolog/monolog 3.12.1 Sends your logs to files, sockets, inboxes, databases and various web services
|--php >=8.1
`--psr/log ^2.0 || ^3.0
   `--php >=8.0.0

O --tree ("árvore") mostra quem depende de quem: o Monolog exige PHP 8.1 ou mais novo e o psr/log na série 2 ou 3.


O composer.lock: a nota fiscal

O composer.json diz "Monolog ^3.12" (qualquer 3.x a partir da 3.12). O composer.lock diz exatamente o que foi instalado:

$ head -c 1200 composer.lock
{
    "_readme": [
        "This file locks the dependencies of your project to a known state",
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
        "This file is @generated automatically"
    ],
    "content-hash": "5a51bab10b23f0846aaa577000df49cb",
    "packages": [
        {
            "name": "monolog/monolog",
            "version": "3.12.1",
            "source": {
                "type": "git",
                "url": "https://github.com/Seldaek/monolog.git",
                "reference": "d7059e4c691d05ea1222b5124bed0f961be46e15"
            },
            …

Versão exata, de onde baixar, e até a "impressão digital" (reference) do código. O aviso no começo resume: "este arquivo trava as dependências do seu projeto num estado conhecido" e "é gerado automaticamente". Nunca edite o composer.lock à mão.

Para que serve? Quando o Bruno, que trabalha com a Ana, baixar o projeto daqui a três meses, o Monolog pode estar na 3.15. Sem o .lock, ele instalaria a 3.15 e a Ana usaria a 3.12: dois computadores com códigos diferentes, e bugs que "só acontecem na máquina dele". Com o .lock, os dois (e o servidor) instalam exatamente a 3.12.1.


composer install × composer update

A pasta vendor/ pode ser apagada e recriada a qualquer momento. É o que acontece quando alguém baixa o projeto do GitHub: o vendor/ não vai junto. Veja:

$ rm -rf vendor
$ php index.php

Warning: require(/home/ana/lojinha/vendor/autoload.php): Failed to open stream: No such file or directory in /home/ana/lojinha/index.php on line 5

Fatal error: Uncaught Error: Failed opening required '/home/ana/lojinha/vendor/autoload.php' (include_path='.:') in /home/ana/lojinha/index.php:5
Stack trace:
#0 {main}
  thrown in /home/ana/lojinha/index.php on line 5
$ composer install
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Package operations: 2 installs, 0 updates, 0 removals
  - Installing psr/log (3.0.2): Extracting archive
  - Installing monolog/monolog (3.12.1): Extracting archive
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!

A primeira linha diz tudo: "Installing dependencies from lock file". O install lê o .lock e instala as versões exatas, sem consultar o que há de novo. Já o update volta ao mercado:

$ composer update
Loading composer repositories with package information
Updating dependencies
Nothing to modify in lock file
Writing lock file
Installing dependencies from lock file (including require-dev)
Nothing to install, update or remove
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.

O update leu o composer.json, procurou no Packagist as versões mais novas permitidas pelo ^ e reescreveu o .lock. Hoje não havia nada mais novo ("Nothing to modify in lock file"); daqui a um mês, ele poderia atualizar o Monolog para 3.13.

composer installcomposer update
LêO composer.lock (se existir)O composer.json
Consulta o Packagist?NãoSim, procura versões novas
Muda o .lock?NãoSim
Quando usarAo baixar o projeto; no servidor; sempre que quiser "o que está combinado"Quando decidir atualizar as bibliotecas, e depois testar
Atualizar só um pacote—composer update monolog/monolog

O que vai para o Git

Se o projeto usa Git, a regra é:

  • composer.json e composer.lock: sim, os dois, sempre.
  • vendor/: não. Coloque /vendor/ no arquivo .gitignore. Quem baixar o projeto roda composer install.

Dependências só de desenvolvimento: --dev

Algumas ferramentas só servem para quem programa: testes automatizados, verificadores de estilo. Elas não precisam ir para o servidor. Instale com --dev:

Por exemplo, composer require --dev phpunit/phpunit. Elas vão para a seção "require-dev". No servidor, composer install --no-dev deixa essas de fora. Você vai instalar o PHPUnit de verdade em Testes com PHPUnit.


O autoload do seu código e o dump-autoload

A seção "autoload" do composer.json diz que Ana\Lojinha\ mora em src/. Foi por isso que new Pedido(…) funcionou sem require: o autoloader do Composer transformou Ana\Lojinha\Pedido em src/Pedido.php, pela regra PSR-4 explicada em Autoload e PSR-4.

  • Criou uma classe nova dentro de src/? Nada a fazer: a regra acha o arquivo.
  • Mudou a seção "autoload" (outro prefixo, outra pasta, uma seção "files")? Rode composer dump-autoload para gerar o autoloader de novo:
$ composer dump-autoload
Generating autoload files
Generated autoload files

Scripts: comandos com nome

A seção "scripts" dá nomes curtos a comandos que você usa sempre. A Ana acrescentou ao composer.json:

    "scripts": {
        "loja": "php index.php",
        "verificar": [
            "@php -l index.php",
            "@php -l src/Pedido.php"
        ]
    }
"loja": "php index.php"
O script loja roda um comando.
"verificar": [ … ]
Um script pode ter vários comandos, numa lista; rodam em ordem.
@php
"O mesmo PHP que está rodando o Composer". O -l (de lint) só confere a sintaxe do arquivo, sem executar.
$ composer validate
./composer.json is valid
$ composer loja
[2026-10-16T23:49:08.982983+00:00] loja.INFO: Pedido fechado {"cliente":"Bruno","total":69.8} []
[2026-10-16T23:49:08.983995+00:00] loja.WARNING: Estoque baixo {"produto":"Caneca","restam":2} []
$ composer verificar
No syntax errors detected in index.php
No syntax errors detected in src/Pedido.php
$ composer run-script --list
scripts:
  loja      Runs the loja script as defined in composer.json
  verificar Runs the verificar script as defined in composer.json 

O composer validate confere se o composer.json está correto; vale rodar depois de editá-lo à mão. Projetos reais costumam ter scripts como "test": "phpunit" e "serve": "php -S localhost:8000 -t public"; o time inteiro passa a usar os mesmos comandos.


Packagist: como escolher um pacote

O packagist.org é onde o Composer procura os pacotes. No site, você busca pelo que precisa ("pdf", "email", "uuid") e vê, para cada pacote, o nome para o composer require, as versões, as dependências e o número de downloads. Antes de instalar, confira:

  • Downloads e estrelas: pacotes muito usados têm mais gente achando e corrigindo erros.
  • Última versão: lançada há meses, não há anos. O composer show monolog/monolog mostra released : 2026-09-29, 2 weeks ago.
  • Versão do PHP exigida ("php": ">=8.1") compatível com a sua.
  • Licença compatível com o seu projeto (MIT, BSD e Apache são as mais tranquilas).
  • Quantas dependências ele traz. Cada uma é mais código de terceiros no seu projeto.

Quando dá errado

Failed opening required '…/vendor/autoload.php'

O que significa: a pasta vendor/ não existe (projeto recém-baixado, ou alguém a apagou).

Como consertar: composer install na pasta do projeto.

Composer could not find a composer.json file
$ cd ..
$ composer install
Composer could not find a composer.json file in /home/ana
To initialize a project, please create a composer.json file. See https://getcomposer.org/basic-usage

O que significa: você rodou o comando fora da pasta do projeto. O Composer sempre trabalha na pasta atual.

Como consertar: cd lojinha e rode de novo (ou composer init, se o projeto ainda não existir).

Could not find a matching version of package
$ composer require ana/nao-existe

In PackageDiscoveryTrait.php line 392:

  Could not find a matching version of package ana/nao-existe. Check the pack
  age spelling, your version constraint and that the package is available in
  a stability which matches your minimum-stability (stable).

require [--dev] [--dry-run] [--prefer-source] … [--] [<packages>...]

O que significa: "não encontrei uma versão compatível do pacote. Confira a grafia, a restrição de versão e se o pacote existe numa versão estável". Quase sempre é nome errado (monolog em vez de monolog/monolog) ou um pacote que só tem versões de teste.

Como consertar: copie o nome exato da página do pacote no Packagist.

does not contain valid JSON
$ composer install

In JsonFile.php line 398:

  "./composer.json" does not contain valid JSON
  Parse error on line 4:
  ...olog": "^3.12",    }}
  ---------------------^
  Expected: 'STRING' - It appears you have an extra trailing comma

O que significa: o composer.json foi editado à mão e ficou com JSON inválido. Aqui, uma vírgula depois do último item (trailing comma), que o PHP aceita em arrays mas o JSON não. A setinha ^ aponta o lugar.

Como consertar: tire a vírgula. Outros erros comuns: aspas simples, comentários, barra invertida simples em "Ana\Lojinha\" (tem que ser \\).

Your requirements could not be resolved to an installable set of packages
$ composer require psr/log:^1.0
./composer.json has been updated
Running composer update psr/log
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires psr/log ^1.0, found psr/log[1.0.0, ..., 1.1.4] but these were not loaded, likely because it conflicts with another require.
  Problem 2
    - monolog/monolog is locked to version 3.12.1 and an update of this package was not requested.
    - monolog/monolog 3.12.1 requires psr/log ^2.0 || ^3.0 -> found psr/log[2.0.0, 3.0.0, 3.0.1, 3.0.2] but it conflicts with your root composer.json require (^1.0).

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.

O que significa: um conflito de versões. A Ana pediu o psr/log 1.x, mas o Monolog 3.12.1 exige o 2.x ou 3.x, e não dá para ter as duas versões ao mesmo tempo. "Root composer.json" é o seu composer.json. A última linha tranquiliza: nada foi alterado.

Como consertar: leia os "Problem" de baixo para cima e escolha versões compatíveis (aqui, simplesmente não pedir o 1.x). O -W deixa o Composer trocar versões de outros pacotes para tentar resolver.


Referência

ComandoO que faz
composer initCria o composer.json (perguntando, ou com --no-interaction)
composer require pacoteAcrescenta ao require e instala
composer require --dev pacoteIdem, em require-dev
composer remove pacoteTira do composer.json e do vendor/
composer installInstala as versões do composer.lock
composer install --no-devIdem, sem as dependências de desenvolvimento (servidor)
composer updateProcura versões novas permitidas e reescreve o .lock
composer show / show --treeLista os pacotes instalados / a árvore de dependências
composer outdatedMostra o que tem versão nova
composer dump-autoloadGera o autoloader de novo
composer validateConfere o composer.json
composer NOME / composer run-script NOMERoda um script da seção "scripts"
composer auditProcura falhas de segurança conhecidas nos pacotes instalados

Exercícios

1. Instalar um pacote

Complete o comando que instala o pacote monolog/monolog:

composer

2. Projeto recém-baixado

Você baixou um projeto do GitHub com composer.json e composer.lock, mas sem vendor/. Qual comando cria a pasta com as versões combinadas?

composer

3. A versão

Escreva a restrição que aceita a versão 2.4 e todas as mais novas, até antes da 3.0:

"vendor/pacote": ""

4. Qual destes arquivos ou pastas não deve ir para o Git?

5. Para que serve o composer.lock?

6. Você pediu monolog/monolog e o Composer instalou também psr/log. Por quê?

Missão final: o Bruno editou o composer.json à mão e o deixou com três erros de JSON: uma vírgula sobrando, aspas simples e uma barra invertida que não foi dobrada. Rode para ver Syntax error, abra a aba composer.json e conserte até o programa mostrar o projeto, a dependência e o autoload.

<?php
$texto = file_get_contents(__DIR__ . '/composer.json');

if (!json_validate($texto)) {
    echo "composer.json inválido: ", json_last_error_msg(), "\n";
    exit(1);
}

$composer = json_decode($texto, true);
echo "Projeto: {$composer['name']}\n";
foreach ($composer['require'] ?? [] as $pacote => $versao) {
    echo "Dependência: $pacote ($versao)\n";
}
foreach ($composer['autoload']['psr-4'] ?? [] as $prefixo => $pasta) {
    echo "Autoload: $prefixo -> $pasta\n";
}
{
    "name": 'ana/lojinha',
    "autoload": {
        "psr-4": {
            "Ana\\Lojinha\": "src/"
        }
    },
    "require": {
        "monolog/monolog": "^3.12",
    }
}
{
    "name": "ana/lojinha",
    "autoload": {
        "psr-4": {
            "Ana\\Lojinha\\": "src/"
        }
    },
    "require": {
        "monolog/monolog": "^3.12"
    }
}

Resumo

  • O Composer baixa pacotes do Packagist, com as dependências deles, para a pasta vendor/, e gera o autoload.
  • composer.json = o que você quer ("require", "autoload", "scripts"); composer.lock = o que foi instalado, versão exata. Os dois vão para o Git; o vendor/, não.
  • composer require pacote instala; ^3.12 aceita atualizações compatíveis até antes da 4.0.
  • install segue o .lock; update procura versões novas e muda o .lock.
  • Um único require __DIR__ . '/vendor/autoload.php'; carrega os pacotes e o seu código (PSR-4 em src/); dump-autoload quando mudar a seção "autoload".
  • "scripts" dá nomes a comandos: composer loja.