Skip to content

florianv/exchanger

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

517 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Exchanger

Tests Psalm Total Downloads Version

Exchange rate provider layer for PHP. Direct access to 30 provider implementations through a single ExchangeRateService interface, with chain fallback and PSR-16 caching. Maintained since 2016.

Exchanger is the exchange rate provider layer for PHP. It exposes 30 services (the European Central Bank, several national banks, exchangerate.host, and commercial exchange rate APIs that require an API key) behind a single ExchangeRateService interface, with chainable fallback, PSR-16 caching, and historical rates. Used in real-world PHP applications since 2016.

For most use cases, the higher-level Swap library is what you want. Reach for Exchanger directly when you need finer control.

πŸ’‘ What is Exchanger?

  • Exchanger is a PHP library for currency conversion and exchange rate retrieval at the provider layer.
  • It contains 30 service implementations behind a common ExchangeRateService interface.
  • It caches results via PSR-16 SimpleCache.
  • It supports historical rates.
  • It supports a chain service for fallback. When a service errors, the next one in the chain is tried.

🎯 When should you use Exchanger?

  • Use Exchanger when you need finer control than Swap exposes: custom chain composition, custom caching strategy, custom HTTP middleware, or building your own facade or framework integration.
  • For most PHP applications, use Swap instead. It is built on Exchanger and provides sensible defaults and a builder-style API.

🧠 Why Exchanger over Swap?

Swap is the easy-to-use, high-level API. Exchanger is the layer Swap is built on.

Reach for Exchanger directly when:

  • Custom facade: you want to build your own currency conversion API on top of the provider layer.
  • Framework binding: you are integrating into a framework that does not yet have a Swap binding.
  • Fine-grained chain composition: you need to wrap services with custom logic (rate limiting, observability, conditional fallback) before chaining them.
  • Direct cache control: you want to manage the PSR-16 cache key strategy yourself.
  • Custom HTTP layer: you need an HTTP middleware stack the Swap builder does not expose.

If none of these apply, use Swap.

πŸ“¦ Installation

Exchanger requires PHP 8.2 or newer.

composer require florianv/exchanger symfony/http-client nyholm/psr7

Any PSR-18 client paired with a PSR-17 request factory works; php-http/discovery finds them automatically.

⚑ Quickstart

use Exchanger\Exchanger;
use Exchanger\ExchangeRateQueryBuilder;
use Exchanger\Service\EuropeanCentralBank;

// The European Central Bank is free, no API key required.
$service   = new EuropeanCentralBank();
$exchanger = new Exchanger($service);

// EUR β†’ USD exchange rate
$query = (new ExchangeRateQueryBuilder('EUR/USD'))->build();
$rate  = $exchanger->getExchangeRate($query);

$rate->getValue();                 // e.g. 1.0823 (a float)
$rate->getDate()->format('Y-m-d'); // e.g. 2026-04-29
$rate->getProviderName();          // 'european_central_bank'

// Convert an amount using the returned rate
$amountInEUR = 100.00;
$amountInUSD = $amountInEUR * $rate->getValue();

// Historical rate
$query = (new ExchangeRateQueryBuilder('EUR/USD'))
    ->setDate((new \DateTime())->modify('-15 days'))
    ->build();

$rate = $exchanger->getExchangeRate($query);

Exchanger retrieves the rate; your application multiplies the amount by $rate->getValue() to perform the conversion.

πŸ” Chaining services (fallback chain)

Wrap multiple services in a Chain to fall back when one of them errors:

use Exchanger\Exchanger;
use Exchanger\Service\Chain;
use Exchanger\Service\EuropeanCentralBank;

$service = new Chain([
    new YourPrimaryService(null, null, ['api_key' => 'YOUR_KEY']),
    new YourFallbackService(null, null, ['api_key' => 'YOUR_KEY']),
    new EuropeanCentralBank(), // free fallback for EUR-base pairs
]);

$exchanger = new Exchanger($service);

Services are tried in order. If a service does not support the requested currency pair, it is skipped silently. If a service throws an exception, the exception is collected and the next service is tried. If every service was skipped or threw, the chain raises an Exchanger\Exception\ChainException containing all collected exceptions.

πŸ›  Common use cases

  • Build your own currency conversion facade on top of the provider layer.
  • Integrate Exchanger into a framework that does not yet have a Swap binding.
  • Wrap services with custom middleware (rate limiting, observability, request signing) before chaining.
  • Power internal FX dashboards with full control over the cache key strategy.
  • Implement custom HTTP layers (signed requests, mTLS, custom retries) on top of any PSR-18 client.

🧭 Which package should I use?

The Swap ecosystem is a layered toolkit for currency conversion in PHP:

  • Swap. The easy-to-use, high-level API. Most apps need only Swap.
  • Exchanger. The lower-level, more granular layer Swap is built on (this package). Reach for it when you need finer control over chain composition, caching, or HTTP plumbing.
  • Laravel Swap. Laravel application of Swap.
  • Symfony Swap. Symfony integration of Swap.

All four packages are MIT-licensed and require PHP 8.2 or newer.

πŸ“Š Providers

Exchanger ships 30 exchange rate provider implementations. Each is registered in Exchanger\Service\Registry under the identifier shown in the table.

Public providers (no API key required)

Service Identifier Base Quote Historical
Bulgarian National Bank bulgarian_national_bank * BGN Yes
Central Bank of the Czech Republic central_bank_of_czech_republic * CZK Yes
Central Bank of the Republic of Turkey central_bank_of_republic_turkey * TRY Yes
Central Bank of the Republic of Uzbekistan central_bank_of_republic_uzbekistan * UZS Yes
Cryptonator cryptonator * (crypto) * (crypto) No
European Central Bank european_central_bank EUR * Yes
exchangerate.host exchangeratehost * * Yes
National Bank of Georgia national_bank_of_georgia * GEL Yes
National Bank of Romania national_bank_of_romania (limited list) (limited list) Yes
National Bank of the Republic of Belarus national_bank_of_republic_belarus * BYN Yes
National Bank of Ukraine national_bank_of_ukraine * UAH Yes
Russian Central Bank russian_central_bank * RUB Yes
WebserviceX webservicex * * No

Commercial providers (require an API key)

Service Identifier Base Quote Historical
AbstractAPI abstract_api * * Yes
coinlayer coin_layer * (crypto) * Yes
Currency Converter API currency_converter * * Yes
Currency Data (APILayer) apilayer_currency_data USD (free), * (paid) * Yes
CurrencyDataFeed currency_data_feed * * No
currencylayer (direct) currency_layer USD (free), * (paid) * Yes
Exchange Rates Data (APILayer) apilayer_exchange_rates_data USD (free), * (paid) * Yes
exchangeratesapi (direct) exchange_rates_api USD (free), * (paid) * Yes
fastFOREX.io fastforex USD (free), * (paid) * No
Fixer (APILayer) apilayer_fixer EUR (free), * (paid) * Yes
Fixer (direct) fixer EUR (free), * (paid) * Yes
1Forge forge * * No
Open Exchange Rates open_exchange_rates USD (free), * (paid) * Yes
xChangeApi.com xchangeapi * * Yes
Xignite xignite * * Yes

You can also add your own provider by implementing the Exchanger\Contract\ExchangeRateService interface (see the documentation).

βš™ Caching, HTTP client, and error handling

  • Caching: PSR-16 SimpleCache is passed as the second constructor argument: new Exchanger($service, $cache). Per-query disable: ->addOption('cache', false). Per-query TTL: ->addOption('cache_ttl', 3600).
  • HTTP client: any PSR-18 client (symfony/http-client, php-http/guzzle7-adapter, etc.). Pass it explicitly to each service constructor, or rely on php-http/discovery to auto-discover.
  • Errors: when every service in a Chain has either skipped (unsupported pair) or thrown, the chain raises an Exchanger\Exception\ChainException containing all collected exceptions.

πŸ“š Documentation

The full documentation, with the per-provider configuration reference, caching options, and how to write your own service, is in doc/readme.md.

🧩 Related packages

The Swap ecosystem:

  • Swap: easy-to-use PHP currency conversion library.
  • Exchanger: exchange rate provider layer (this package).
  • Laravel Swap: Laravel application of Swap.
  • Symfony Swap: Symfony integration of Swap.

🀝 Sponsorship

The Swap ecosystem is open to selected sponsorships from exchange rate API providers and financial infrastructure companies.

Sponsorship can include:

  • Documentation visibility
  • Integration examples
  • Ecosystem-level visibility across Swap, Exchanger, Laravel Swap, and Symfony Swap

For inquiries, contact the maintainer via GitHub.

πŸ™Œ Contributing

Issues and pull requests are welcome. Please see the existing issues before opening a new one.

πŸ“„ License

The MIT License (MIT). Please see LICENSE for more information.

πŸ‘ Credits

About

PHP exchange rate provider layer for currency conversion: 30 services, chain fallback, and caching.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors