Framework Documentation - Application Package
Updating from v3 to v4
Release 4.0.0 raises the PHP requirement and removes the two backwards compatibility shims that
were deprecated in 2.0. Both removals are mechanical to fix, and both can be fixed while still on
3.x.
At a glance
| v3 (3.0.4) | v4 (4.0.0) | |
|---|---|---|
| PHP | ^8.1.0 |
^8.3.0 |
$app->input magic getter |
deprecated, works | removed |
Boolean $status in redirect() |
deprecated, works | removed |
psr/http-message |
^1.0 |
^2.0 |
laminas/laminas-diactoros |
^2.24.0 |
^3.6.0 |
Minimum supported PHP version raised
All Framework packages now require PHP 8.3 or newer.
Access to input data
AbstractWebApplication::__get() has been removed. It existed solely as a compatibility proxy that
mapped $app->input to getInput() and emitted a deprecation notice. Reading the property now
raises a PHP warning and evaluates to null, so the failure surfaces later as a call on null:
// Old — removed in 4.0.0
$app->input->getInt('id');
// New
$app->getInput()->getInt('id');Because the magic getter also handled every other property name with an E_USER_NOTICE, any other
undefined property read on the application now follows normal PHP semantics.
To find the call sites before upgrading:
grep -rn -- '->input->' src/Status on redirect
redirect() no longer accepts a boolean $status. In 1.x, true meant "301 Moved Permanently"
and false meant "303 See Other"; 2.0 deprecated that and 4.0 removed the translation. Pass the
HTTP status code:
// Old — removed in 4.0.0
$app->redirect('/target', true); // meant 301
$app->redirect('/target', false); // meant 303
// New
$app->redirect('/target', 301);
$app->redirect('/target', 303);The docblock type narrowed from integer|boolean to integer in both
AbstractWebApplication::redirect() and WebApplicationInterface::redirect().
A boolean now fails loudly: the guard is
if (!\is_int($status) && !$this->isRedirectState($status)), and isRedirectState() casts to int
first, so true becomes 1, fails the > 299 test, and an InvalidArgumentException is thrown.
Note that the same guard accepts any integer, including non-redirect codes —
redirect($url, 200)
passes and sends aLocationheader with status 200. Only booleans and other non-integers are
rejected. Pass a real 3xx code.
PSR-7 2.0
psr/http-message moved from ^1.0 to ^2.0, and laminas/laminas-diactoros from ^2.24 to
^3.6.
PSR-7 2.0 adds return types to every interface method. This affects you if you implement any
PSR-7 interface yourself — a custom ResponseInterface passed into the application constructor,
or a decorator around one:
// PSR-7 1.x
public function withStatus($code, $reasonPhrase = '')
// PSR-7 2.0
public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterfaceConsuming a PSR-7 object needs no change. If you only pass Diactoros objects around, upgrading the
dependency is enough.
Dependency changes
| Package | v3 (3.0.4) | v4 (4.0.0) |
|---|---|---|
php |
^8.1.0 |
^8.3.0 |
psr/http-message |
^1.0 |
^2.0 |
laminas/laminas-diactoros |
^2.24.0 |
^3.6.0 |
joomla/event |
^3.0 |
^4.0 |
joomla/registry |
^3.0 |
^4.0 |
psr/log |
^1.0 | ^2.0 | ^3.0 |
unchanged |
symfony/deprecation-contracts |
^2 | ^3 |
unchanged |
Optional packages in suggest:
| Package | v3 (3.0.4) | v4 (4.0.0) |
|---|---|---|
joomla/controller |
^3.0 |
^4.0 |
joomla/input |
^3.0 |
^4.0 |
joomla/router |
^3.0 |
^4.0 |
joomla/session |
^3.0 |
^4.0 |
joomla/uri |
^3.0 |
^4.0 |
psr/container |
^1.0 |
^2.0 |
psr/container 2.0 also adds return types (has(string $id): bool, get(string $id): mixed).
This matters only if you pass a hand-written container to ContainerControllerResolver.