Cache HTTP
O sistema de cache é utilizado para armazenar respostas dinâmicas, utilizando If-None-Match (ETag) ou If-Modified-Since
para permitir o envio de uma resposta HTTP 304.
Armazenando resposta em cache
Inicia o buffer para criar cache da resposta:
use Inphinit\Experimental\Http\Cache;
$cacher = new Cache();
$result = $cacher->start();
if ($result === Cache::FAILED) {
error_log('Cache failed', 0);
} elseif ($result === Cache::CACHED) {
// Se já estiver em cache, o processamento pode ser encerrado antecipadamente.
exit;
}
echo gmdate('M d Y H:i:s e'), "\n";
echo str_repeat("Hello!\n", 500);
// O uso de stop() é geralmente opcional, mas é recomendado para proporcionar maior controle ao desenvolvedor.
$cacher->stop();
Resposta HTTP:
HTTP/1.1 200 OK
Host: localhost:5000
Cache-Control: public, max-age=3600
Expires: Thu, 01 Oct 2026 19:15:25 GMT
Last-Modified: Thu, 01 Oct 2026 19:14:55 GMT
Etag: "ec6bf505c3767e7598eb89876a52d97c86d42613c6b1a555d525a0a4c0b65601"
Content-type: text/html; charset=UTF-8
Ambiente de desenvolvimento
No ambiente de desenvolvimento, quando usado a variavel de ambiente APP_ENVIRONMENT=development,
o header X-Inphinit-Experimental-Cache será enviado, para identificar se a resposta foi gerada
na atual requisição, ou se ela veio do cache armazenado, retornando algo como:
HTTP/1.1 200 OK
Host: localhost:5000
Cache-Control: public, max-age=3600
Expires: Thu, 01 Oct 2026 19:15:25 GMT
Last-Modified: Thu, 01 Oct 2026 19:14:55 GMT
Etag: "ec6bf505c3767e7598eb89876a52d97c86d42613c6b1a555d525a0a4c0b65601"
X-Inphinit-Experimental-Cache: writing
Content-type: text/html; charset=UTF-8
Possiveis valores no header X-Inphinit-Experimental-Cache:
| Header | Descrição |
|---|---|
X-Inphinit-Experimental-Cache: cached |
Se a resposta exibida na requisição atual é provida a partir do cache |
X-Inphinit-Experimental-Cache: failed |
Se qualquer coisa falhar ao iniciar o armazenamento da resposta em cache |
X-Inphinit-Experimental-Cache: writing |
Se a resposta atual não for o cache, mas a gravação do cache inicio, para ser usado nas próximas requisições |
Configurando o armazenamento
Se você precisar criar caches separados para diferentes usuários ou cenários para evitar conflitos, pode alterar o local de armazenamento, separando os caches em diretórios diferentes, conforme mostrado no exemplo:
use Inphinit\Experimental\Http\Cache;
use Inphinit\Experimental\Utility\Storage;
$user_path = 'storage/output/' . $user_id;
if (Storage::mkdir($user_path)) {
$cacher = new Cache(null, null, $user_path);
if ($cacher->start() === Cache::CACHED) {
exit;
}
} else {
$cacher = null;
}
echo gmdate('M d Y H:i:s e'), "\n";
echo str_repeat("Hello!\n", 500);
if ($cache !== null) {
$cacher->stop();
}
Realizando testes
Para executar testes (como testes de unidade) fora do contexto web, é possível passar explicitamente os valores de método e caminho, como no exemplo:
use Inphinit\Experimental\Http\Cache;
use Inphinit\Experimental\Utility\Storage;
$tests_path = 'storage/output/tests/';
if (Storage::mkdir($tests_path) === false) {
throw \RuntimeException('Failed to create folder');
}
$cacher = new Cache('GET', '/fake_path?a=1&b=2', $tests_path);
$result = $cacher->start();
my_assert($result !== Cache::FAILED);
echo gmdate('M d Y H:i:s e'), "\n";
echo str_repeat("Hello!\n", 500);
$cacher->stop();
Usando rotas
Exemplo de uso com rotas:
use Inphinit\Experimental\Http\Cache;
$app->action(['GET', 'HEAD'], '/vehicle/<id:uuid>.html', function (App $app, array $params) {
$cacher = new Cache();
$result = $cacher->start();
echo 'Hour: ', gmdate('M d Y H:i:s e');
$cacher->stop();
});
Utilizando controladores de rotas
Exemplo de controlador:
<?php
namespace Controllers;
use Inphinit\Experimental\Http\Cache;
class MyController
{
private $cacher;
public function __construct()
{
$this->cacher = new Cache();
if ($this->cacher->start() === Cache::CACHED) {
exit;
}
}
public function __destruct()
{
$this->cacher->stop();
}
public function foo($app, $params)
{
return 'Foo!';
}
public function bar($app, $params)
{
return 'Bar!';
}
}
Adicionandos controlador para as rotas:
<?php
$app->action('GET', '/sample/foo', 'MyController::foo');
$app->action('GET', '/sample/bar', 'MyController::bar');
Extendendo a classe Cache
Exemplo de uso:
use Inphinit\Experimental\Http\Cache;
class MyOwnCache
{
protected static function match($etag, $modified)
{
// Só valida Etag, ignorando o uso de If-Modified-Since
return Request::header('If-None-Match') === "\"{$etag}\"";
}
protected static function valid($method)
{
// Só criar cache para requisições com método HTTP query
return $method === 'QUERY';
}
protected static function createHash($path)
{
// Utilizando SHA-384
return \hash('sha384', $path);
}
}
$cacher = new MyOwnCache();
$result = $cacher->start();
if ($result === Cache::CACHED) {
exit;
}
...
API
A seguir a explicação de uso dos métodos da classe Inphinit\Experimental\Http\Cache
| Use | Description |
|---|---|
__construct(string $method = null, string $path = null, string $storage = null) |
|
setWriter(callable $callback) |
Define um callback para sobreescrever o buffer a cada flush (depende do parametro $chuckSize no método start($expires, $chuckSize)).
|
start(int $expires = 3600, int $chuckSize = 1024): int |
Inicia o buffer para ser gravado no cache.
|
stop() |
Encerra o buffer |
protected static function match(string $etag, int $modified): bool |
Verifique o cabeçalho If-None-Match em relação ao ETag e o If-Modified-Since em relação à data e hora de modificação do cache. Opicionalmente esse método pode ser sobreescrito em uma classe extendida.
|
protected static function valid(string $method): bool |
Verifica se é HEAD ou GET – Este método pode ser sobrescrito. Opicionalmente esse método pode ser sobreescrito para aceitar outros métodos em uma classe extendida. |
protected static function createHash(string $path): string |
Cria as hashes usados em caches e ETags. Opicionalmente esse método pode ser sobreescrito em uma classe extendida. |