PHPackages                             joefallon/phpcache - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Caching](/categories/caching)
4. /
5. joefallon/phpcache

ActiveLibrary[Caching](/categories/caching)

joefallon/phpcache
==================

This package contains a tag-based cache (APC only).

v4.0.1(7mo ago)336MITPHPPHP &gt;=7.4.0

Since Jul 15Pushed 7mo ago2 watchersCompare

[ Source](https://github.com/joefallon/phpcache)[ Packagist](https://packagist.org/packages/joefallon/phpcache)[ Docs](https://github.com/joefallon/phpcache)[ RSS](/packages/joefallon-phpcache/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependencies (1)Versions (15)Used By (0)

Joe's PHP Cache
===============

[](#joes-php-cache)

A simple, dependency-free PHP library that adds tagging and namespacing on top of a small key/value cache backend (APCu by default). It provides a lightweight, easy-to-integrate TaggedCache for invalidating groups of cache entries by tag, plus a thin `ApcCache` adapter that uses APCu as the backing store.

Why use this library?

- Tag-based invalidation: clear groups of related cache entries with a single call.
- Namespaces: isolate caches within the same backing store (useful for multi-tenant apps or tests).
- Minimal and portable: back-end is pluggable via the `Cacheable` interface, so you can add other adapters.

Quick status
------------

[](#quick-status)

- Package: `joefallon/phpcache`
- License: MIT
- Requires: PHP 7.4+ (uses typed properties)
- Optional extension: APCu (for `ApcCache`)

Installation
------------

[](#installation)

Require the package via Composer:

```
composer require joefallon/phpcache
```

(If you're developing locally, you can also clone the repo and include it with Composer using path repositories.)

Note: To use the included `ApcCache` you must have the APCu extension enabled (CLI and/or FPM depending on your environment). If APCu isn't available, implement the `JoeFallon\PhpCache\Cacheable` interface to plug in another backend (Redis, Memcached, filesystem, etc.).

Basic usage
-----------

[](#basic-usage)

This example shows the two main classes included in the package: `ApcCache` (back-end) and `TaggedCache` (feature layer).

Example — non-tagged value:

```
use JoeFallon\PhpCache\ApcCache;
use JoeFallon\PhpCache\TaggedCache;

$backing = new ApcCache();
$cache = new TaggedCache($backing); // default namespace and default expiration

$cache->store('user_45_profile', $profileData);
if ($cache->exists('user_45_profile')) {
    $profile = $cache->retrieve('user_45_profile');
}

$cache->remove('user_45_profile');
```

Example — tagged values and bulk invalidation:

```
use JoeFallon\PhpCache\ApcCache;
use JoeFallon\PhpCache\TaggedCache;

$cache = new TaggedCache(new ApcCache());

$cache->store('all_posts', $postsList, ['posts_table']);
$cache->store('post_45', $singlePost, ['posts_table']);

// Later, when posts are modified, invalidate everything tagged with 'posts_table':
$cache->removeByTag('posts_table');
```

Namespaces
----------

[](#namespaces)

`TaggedCache` supports a namespace string passed to its constructor. Namespacing is applied to all keys and tag lists, so you can safely use multiple independent caches in the same backing store:

```
$cacheA = new TaggedCache(new ApcCache(), 'siteA');
$cacheB = new TaggedCache(new ApcCache(), 'siteB');
```

Expiration (TTL)
----------------

[](#expiration-ttl)

- `TaggedCache` accepts an optional `defaultExpiresInSeconds` in its constructor (defaults to 1 year).
- When storing an entry you may supply a custom TTL (seconds) as the 4th argument of `store()`; passing `0` uses the cache's default TTL.

Example (custom TTL):

```
$cache = new TaggedCache(new ApcCache(), '', 3600); // default TTL = 1 hour
$cache->store('weather', $data, null, 300); // expires in 5 minutes
```

Storage format (implementation note)
------------------------------------

[](#storage-format-implementation-note)

Entries saved by `TaggedCache` are stored in the underlying `Cacheable` using a small associative structure with the following keys:

- `expires` — timestamp string when the entry should be considered expired;
- `tags` — null or array of tag names attached to this entry;
- `value` — the original value saved by the caller.

This is internal implementation detail but useful to know if you inspect the backing store directly.

Public API (main methods)
-------------------------

[](#public-api-main-methods)

- `store(string $key, $value, array $tags = null, int $expiresInSeconds = 0)` — store a value. Tags are optional. If `$expiresInSeconds` is `0` the cache's default is used.
- `retrieve(string $key)` — returns the stored value or `null` if missing or expired.
- `exists(string $key)` — returns `true` if the key exists and is not expired.
- `remove(string $key)` — removes the key and removes it from any tag lists.
- `removeByTag(string $tag)` — removes all keys that were stored with the given tag.
- `removeAll()` — removes every key previously stored through this `TaggedCache` instance (it relies on an internal ALL\_KEYS list).

Best practices and gotchas
--------------------------

[](#best-practices-and-gotchas)

- APCu is shared across the process: if you run PHP-FPM and also use CLI scripts, make sure APCu is enabled for the environment you expect. On some systems CLI APCu is disabled by default.
- Storing `null` as a value: the library stores `null` values correctly; `exists()` will return `true` for a saved `null` (it reflects presence, not non-nullness). `retrieve()` will return `null` in that case.
- Avoid long-lived in-memory caches for highly dynamic data; use shorter TTLs and explicit tag invalidation when appropriate.
- When writing integration tests, pass a namespace to `TaggedCache` to avoid clobbering other tests or host caches.

Implementing a custom backend
-----------------------------

[](#implementing-a-custom-backend)

If you can't or don't want to use APCu, implement the `JoeFallon\PhpCache\Cacheable` interface and pass your adapter into `TaggedCache`. The interface is intentionally small:

- `store(string $key, $value)`
- `retrieve(string $key)`
- `exists(string $key): bool`
- `remove(string $key)`
- `removeAll()`

A custom adapter lets you use Redis, Memcached, or a filesystem-based cache.

Testing locally
---------------

[](#testing-locally)

The project now uses PHPUnit (v9.6) for unit tests. Run the test suite using the repository-installed PHPUnit binary:

```
# install dependencies (including dev deps) if needed
composer install --no-interaction

# run PHPUnit with the repository configuration
vendor/bin/phpunit --configuration phpunit.xml.dist
```

Notes:

- PHPUnit 9.6 supports PHP 7.4 through 8.2. Ensure your PHP runtime is within that range when running tests.
- The test bootstrap (`tests/bootstrap.php`) provides an APCu polyfill when the `apcu` extension is not available or not enabled for CLI. If you have APCu installed and enabled for CLI (`apc.enable_cli=1`), native APCu will be used instead.
- The previous KissTest harness has been removed as part of the migration — see `CHECKLIST.md` for migration details.

Troubleshooting
---------------

[](#troubleshooting)

- "Class not found" errors when running the examples or tests? Ensure Composer's autoloader is included:

```
require_once __DIR__ . '/vendor/autoload.php';
```

- APCu functions not found? Ensure the `apcu` extension is installed and enabled for the PHP SAPI you are using. On Debian/Ubuntu:

```
sudo apt-get install php-apcu
# or for a specific PHP version, e.g. php8.1-apcu
sudo apt-get install php8.1-apcu
```

- Stale items remain after `removeByTag` / `removeAll`? Ensure you are using the same namespace and that your adapter supports removing individual keys. If you implemented a custom adapter, verify its `remove()` and `store()` behavior.

Contributing
------------

[](#contributing)

Contributions are welcome. Some suggestions:

- Add adapters for other cache backends (Redis, Memcached, file).
- Improve tests and CI configuration.
- Fix bugs or improve the API ergonomics.

Please fork, open a feature branch, and submit a pull request. Keep changes small and include tests.

License
-------

[](#license)

This project is licensed under the MIT license — see the `LICENSE` file for details.

Acknowledgements
----------------

[](#acknowledgements)

Inspired by the need to tag and invalidate groups of cache entries when related data changes. If you find this useful, please star the repository and consider contributing improvements or adapters for other backends.

Contact / Support
-----------------

[](#contact--support)

If you need help integrating the library, open an issue with a minimal reproducible example and I'll take a look.

---

**Built with ❤️ and the KISS principle.**

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance64

Regular maintenance activity

Popularity11

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~342 days

Recently: every ~978 days

Total

13

Last Release

217d ago

Major Versions

v1.1.0 → v2.0.02014-10-28

v2.0.4 → v3.0.02016-08-22

v3.0.0 → v4.0.02025-10-12

PHP version history (2 changes)v1.0.0PHP &gt;=5.3.0

v4.0.0PHP &gt;=7.4.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/97cecfa80ffec8e9e7b5d0ff6df026b636e31a15fe0c2155baba402b5d4f0819?d=identicon)[joefallon](/maintainers/joefallon)

---

Top Contributors

[![joefallon](https://avatars.githubusercontent.com/u/4212989?v=4)](https://github.com/joefallon "joefallon (20 commits)")

---

Tags

phpcachetagsapc

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/joefallon-phpcache/health.svg)

```
[![Health](https://phpackages.com/badges/joefallon-phpcache/health.svg)](https://phpackages.com/packages/joefallon-phpcache)
```

###  Alternatives

[awssat/laravel-visits

Laravel Redis visits counter for Eloquent models

975163.6k2](/packages/awssat-laravel-visits)[swayok/alternative-laravel-cache

Replacements for Laravel's redis and file cache stores that properly implement tagging idea. Powered by cache pool implementations provided by http://www.php-cache.com/

202541.1k6](/packages/swayok-alternative-laravel-cache)[tedivm/stash-bundle

Incorporates the Stash caching library into Symfony.

841.4M16](/packages/tedivm-stash-bundle)[eftec/cacheone

A Cache library with minimum dependency

103.5k4](/packages/eftec-cacheone)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
