Download the PHP package otherguy/php-currency-api without Composer
On this page you can find all versions of the php package otherguy/php-currency-api. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download otherguy/php-currency-api
More information about otherguy/php-currency-api
Files in otherguy/php-currency-api
Package php-currency-api
Short Description A PHP API Wrapper to offer a unified programming interface for popular Currency Rate APIs.
License MIT
Informations about the package php-currency-api
💱 PHP Currency API
A PHP API Wrapper offering a unified, fluent programming interface for popular currency exchange rate APIs.
Don't worry about your favorite currency conversion service shutting down or changing plans. Switch providers without changing your code.
What's new in 2.0
- PHP 8.3+ with strict types everywhere.
- PSR-18 / PSR-17 HTTP layer — bring your own client (Guzzle, Symfony, anything PSR-compliant).
brick/mathBigDecimalfor precise rate math instead of floats.Currencybacked enum replaces the oldSymbolconstants class (which is kept as a deprecation shim).- New
frankfurterdriver — free, no API key required. - New
currencyapiandfastforexdrivers — provider parity with TripTally's backend FX stack. - Rewritten
exchangeratesapidriver — now points at the workingapi.apilayer.comendpoint with fullconvert()support. - Pluggable
DriverFactory— register your own provider at runtime.
You can find detailed instructions on how to upgrade from 1.x to 2.x in UPGRADING.md.
Features
- Multiple drivers behind a single interface — switch providers by changing one string.
- Fluent setter chain (
source,to,amount,date, …) on every driver. ConversionResultvalue object with lossless rebasing (setBaseCurrency()).- Hermetic test surface — inject any PSR-18 client, including in-memory mocks.
Supported APIs
| Service | Identifier |
|---|---|
| Frankfurter | frankfurter |
| FixerIO | fixerio |
| CurrencyLayer | currencylayer |
| Open Exchange Rates | openexchangerates |
| APILayer Exchange Rates | exchangeratesapi |
| CurrencyAPI | currencyapi |
| fastFOREX | fastforex |
A mock driver is also bundled for testing without network access.
Want another provider? Open an issue — or register a custom driver at runtime (see below).
Requirements
- PHP 8.3 or higher.
- A PSR-18 HTTP client and PSR-17 request factory of your choice.
- An API account with the chosen provider, except for
frankfurter.
Installation
You also need a PSR-18 client and PSR-17 factory. The most common choice is Guzzle:
Alternatively, with Symfony HttpClient:
Quickstart
DriverFactory::make() auto-discovers Guzzle if it's installed and wires up a default PSR-18 client. To inject your own:
Bring your own HTTP client (Symfony + nyholm/psr7)
Usage
The Currency enum
Otherguy\Currency\Currency is a backed enum with one case per ISO-4217 code (plus a few common crypto/precious-metal codes).
Every method that takes a currency accepts either the enum or its string code, so plain 'USD' keeps working.
Setting the access key
Most providers require authentication. accessKey() is sugar for config('access_key', …) and is wired per-driver to the right query-string parameter.
Frankfurter has no API key — calling accessKey() on it throws ApiException. CurrencyAPI is the exception to the query-string rule: its driver sends the key in the apikey request header.
Provider-specific key mapping:
| Driver | accessKey() mapping |
|---|---|
fixerio |
access_key query parameter |
currencylayer |
access_key query parameter |
openexchangerates |
app_id query parameter |
exchangeratesapi |
apikey query parameter |
currencyapi |
apikey request header |
fastforex |
api_key query parameter |
frankfurter |
no key; throws ApiException |
Configuration options
For provider-specific options use config():
Base currency
from() and source() are aliases.
Each driver has its own default base currency: EUR for FixerIO, APILayer Exchange Rates, and Frankfurter; USD for CurrencyLayer, Open Exchange Rates, CurrencyAPI, fastFOREX, and the mock driver. Most providers only allow base-currency changes on paid plans — they'll respond with an error envelope which the driver translates into ApiException.
Target currencies
to() and currencies() are aliases. Pass a single currency or an array. Pass nothing (or an empty array) to ask for every currency the provider supports.
Latest rates
Historical rates
Dates must be DateTimeInterface (or null).
Convert amount
For providers without a native /convert endpoint (e.g. Frankfurter), the driver fetches the rate via get() / historical() and returns a ConversionResult for the requested pair. Use ConversionResult::convert() when you need the converted amount as a BigDecimal.
CurrencyAPI and fastFOREX both expose native latest conversion endpoints. For dated conversions, their drivers fetch historical rates and return a ConversionResult for the requested pair.
Fluent chain
ConversionResult
get() and historical() return a ConversionResult. Rates are stored as BigDecimal and rebasing is lossless (default scale: 8 decimals).
rate() on a code that wasn't fetched throws Otherguy\Currency\Exceptions\CurrencyException. To convert between two arbitrary currencies, request both in the original get() / historical() call.
Registering custom drivers
The factory is instance-based. Bring your own driver class (extending BaseCurrencyDriver) and register it:
The static DriverFactory::make($name) continues to work via a process-wide default factory — DriverFactory::setDefault($factory) lets you swap it for tests.
Adding a new driver
A driver is the bridge between this library's fluent interface and a specific upstream rate provider. Every driver implements BaseCurrencyDriver.
The base class supplies:
- All fluent setters (
source,from,currencies,to,amount,date,config,accessKey,secure). - A PSR-18 / PSR-17 HTTP layer in
apiRequest()that builds the URI, merges$httpParamswith per-call params, decodes JSON withJSON_THROW_ON_ERROR, and wraps every failure mode inApiException.
You only need to:
- Set the right defaults for
$apiURL,$protocol, and$baseCurrency. - Implement
get(),historical(), andconvert(). - Override
apiRequest()only if the provider's successful HTTP response can still carry an error envelope, such assuccess: false.
Driver skeleton
For providers without a native conversion endpoint, fetch rates through get() / historical() and return the resulting ConversionResult; Frankfurter is the compact example.
Driver authentication
accessKey() defaults to writing access_key=... into $httpParams. If your provider uses a different parameter name, override it:
For header authentication, write to $httpHeaders:
If the provider has no keys, throw to make misuse loud:
Provider-specific error envelopes
Many providers return HTTP 200 with an error body. Override apiRequest() to translate those into ApiException before the value reaches get() / historical() / convert():
First-party driver registration
For first-party drivers shipped with this package, add the class to the built-in map in DriverFactory:
For third-party drivers, use runtime registration as shown above. register() returns $this, unregister(string $name) removes a driver, and build() accepts optional PSR-18 + PSR-17 collaborators. If those collaborators are omitted, the factory tries to auto-discover Guzzle.
Driver tests
Driver tests live under tests/Drivers/. Use tests/Support/DriverHarness.php to wire up an in-process PSR-18 mock:
DriverHarness instantiates a fresh MockHttpClient on each test. Use enqueue() to queue responses, lastRequest() to assert URI/query/headers, and sentRequests() for multi-request flows.
Driver checklist
- [ ]
declare(strict_types=1)andOverrideattributes where you override. - [ ]
$apiURLdoes not include thehttps://prefix;BaseCurrencyDriveradds the protocol. - [ ]
get(),historical(), andconvert()returnConversionResult, not arrays. - [ ] Error envelopes are wrapped in
ApiExceptionso callers see one consistent failure type. - [ ] PHPStan is clean at
level: max(composer analyse). - [ ] Tests cover happy path, error envelope, and any
accessKey()quirks. - [ ] First-party drivers are registered in
DriverFactoryand listed in the Supported APIs table.
For real examples, browse the existing drivers. They range from thin happy-path code in ExchangeRatesApi.
Testing
The library exposes Otherguy\Currency\Drivers\MockCurrencyDriver for consumers writing tests without a network. Seed it with rates and use it like any other driver:
For testing this library itself, see tests/Support/MockHttpClient.php — a tiny in-process PSR-18 double that records sent requests and replays queued responses. CONTRIBUTING.md walks through it.
Project commands
| Command | What it does |
|---|---|
composer test |
Run the test suite |
composer test:coverage |
Run with coverage (requires Xdebug) |
composer lint |
Pint code-style check (read-only) |
composer lint:fix |
Pint auto-fix |
composer analyse |
PHPStan at level max |
composer rector |
Rector dry-run |
composer rector:fix |
Rector apply |
composer check |
All of the above, in order |
Contributing
Pull requests are welcome — please run composer check before opening one. Coverage target is ≥ 98% on src/. See CONTRIBUTING.md for the full guide.
License
MIT.
All versions of php-currency-api with dependencies
ext-json Version *
brick/math Version ^0.17
psr/http-client Version ^1.0
psr/http-factory Version ^1.1
psr/http-message Version ^1.1 || ^2.0