An open API service indexing awesome lists of open source software.

https://github.com/terrylinooo/simple-cache

PSR-16 simple cache drivers for PHP.
https://github.com/terrylinooo/simple-cache

php-cache php-mongodb php-redis psr-16 simple-cache

Last synced: 16 days ago
JSON representation

PSR-16 simple cache drivers for PHP.

Awesome Lists containing this project

README

        

# PSR-16 Simple Cache

| GitHub Action | Travis CI | Scrutinizer CI | Code Coverage | Code Quality |
| ------------- | --------- | --------------- | ------------- | ------------ |
| ![build](https://github.com/terrylinooo/simple-cache/workflows/build/badge.svg?branch=master) | [![Build Status](https://travis-ci.org/terrylinooo/simple-cache.svg?branch=master)](https://travis-ci.org/terrylinooo/simple-cache) | [![Build Status](https://scrutinizer-ci.com/g/terrylinooo/simple-cache/badges/build.png?b=master)](https://scrutinizer-ci.com/g/terrylinooo/simple-cache/build-status/master) | [![codecov](https://scrutinizer-ci.com/g/terrylinooo/simple-cache/badges/coverage.png?b=master)](https://codecov.io/gh/terrylinooo/simple-cache) | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/terrylinooo/simple-cache/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/terrylinooo/simple-cache/?branch=master)

Caching, a common performance-boosting technique, is a staple feature in many frameworks and libraries. This interoperability allows libraries to utilize existing caching implementations rather than creating their own. PSR-6 has addressed this issue, but its formal and verbose nature complicates simple use cases. PSR-16 is a simpler approach seeks to create a streamlined standard interface for common situations, ensuring compatibility with PSR-6 in a straightforward manner.

***Showcase***

Simple Cache is utilized in [Cache Master](https://github.com/terrylinooo/cache-master), a [WordPress Cache Plugin](https://wordpress.org/plugins/cache-master/), and it performs excellently. Check it out if you're running WordPress sites; it won't let you down.

#### Built-in drivers:

The required parameters are marked by an asterisk (*)

| Driver name | `($driver)` | PHP modules | `($config)` |
| ------------ | ----------- | ----------- | --------------------------------------------------------------------- |
| File | `file` | - | `*storage` |
| Redis | `redis` | redis | `host`, `port`, `user`, `pass`, `unix_socket` |
| MongoDB | `mongo` | mongodb | `host`, `port`, `user`, `pass`, `dbname`, `collection`, `unix_socket` |
| MySQL | `mysql` | pdo_mysql | `host`, `port`, `*user`, `*pass`, `*dbname`, `table`, `charset` |
| SQLite | `sqlite` | pdo_sqlite | `*storage` |
| APC | `apc` | apc | - |
| APCu | `apcu` | apcu | - |
| Memcache | `memcache` | memcache | `host`, `port`, `unix_socket` |
| LibMemcached | `memcached` | memcached | `host`, `port`, `unix_socket` |
| WinCache | `wincache` | wincache | - |

Note:

- **WinCache** is excluded from unit testing since it's only used on Windows, and the testing processes are done on Linux environment.
- `unix_socket` is empty by default, accepting the absolute path of the unix domain socket file. If it is set, `host` and `port` will be ignored.

The following command displays a list of installed PHP modules.

```bash
php -m
```
Before using, make sure the required PHP modules are installed on your system.

---

## Table of Contents

- Install
- Usage
- Cache
- Built-in drivers
- __construct
- $driver
- $config
- API
- set
- get
- has
- delete
- getMultiple
- setMultiple
- deleteMultiple
- clear
- clearExpiredItems `(Non-PSR-16)`
- Build Data Schema
- MySQL
- SQLite
- Garbage Collection
- Author
- License

---

## Install

```bash
composer require shieldon/simple-cache
```

## Usage

### `Cache`

Class `Cache` is an adapter that not only allows the implemented instance of `Psr\SimpleCache\CacheInterface`, but also has built-in drivers already.

#### __construct(`$driver = ''`, `$config = []`)

Create a cache handler using the file driver.

Example:

```php
$driver = new \Shieldon\SimpleCache\Cache('file', [
'storage' => __DIR__ . '/../tmp'
]);
```

#### `$driver`

(string|CacheInterface)

The class name of a built-in driver, or a PSR-16 driver that implements `Psr\SimpleCache\CacheInterface`.

#### `$config`

(array)

An array of parameters will be passed to a built-in driver.

Example:

*Redis*
```php
$config = [
'host' => '127.0.0.1',
'port' => 6379,
'user' => null,
'pass' => null,
];
```

*File*
```php
$config = [
'storage' => '/tmp/simple-cache',
];
```

*Mysql*
```php
$config = [
'host' => '127.0.0.1',
'port' => 3306,
'user' => null,
'pass' => null,
'dbname' => null,
'table' => 'cache_data',
'charset' => 'utf8'
];
```

*Sqlite*
```php
$config = [
'storage' => '/tmp/simple-cache',
];
```

*Mongo*
```php
$config = [
'host' => '127.0.0.1',
'port' => 27017,
'user' => null,
'pass' => null,
'database' => 'test',
'collection' => 'cache_data',
];
```

*Memcache*, *Memcached*
```php
$config = [
'host' => '127.0.0.1',
'port' => 11211,
];
```

---

## API

Those API methods are defined on `Psr\SimpleCache\CacheInterface`. Please check out the [PSR-16 document](https://www.php-fig.org/psr/psr-16/) to get the detailed explanation.

- set
- get
- has
- delete
- setMultiple
- getMultiple
- deleteMultiple
- clear
- clearExpiredItems *(Non-PSR-16)*

### set

```php
public function set(string $key, mixed value, $ttl = null);
```

Note that **$ttl** accepts `null`,`int`,`DateInterval`.
The `null` means that the key never expires until deleted.

Example:

```php
$cache->set('foo', 'bar', 300);
$cache->set('foo2', 'bar2');

$array = [
'hello' => 'world',
'yes' => 'Taiwan',
];

$cache->set('foo3', $array);
$cache->set('foo4', $array, 300);
```

### get

```php
public function get(string $key, mixed $default = null): mixed
```

Example:

```php
echo $cache->get('foo', 'placeholder');
// bar

sleep(301);

echo $cache->get('foo', 'placeholder');
// placeholder

echo $cache->get('foo');
// null

echo $cache->get('foo2', 'placeholder');
// bar2

$example = $cache->get('foo3', 'placeholder');
var_dump($example);
// string(11) "placeholder"

$example = $cache->get('foo4', 'placeholder');
var_dump($example);
/*
array(2) {
["hello"]=>
string(5) "world"
["yes"]=>
string(6) "Taiwan"
}
*/
```

### has

```php
public function has(string $key): bool
```

Example:

```php
if ($cache->has('foo3')) {
echo 'foo3 exists.';
} else {
echo 'foo3 does not exist.';
}
// foo3 exists.
```

### delete

```php
public function delete(string $key): bool
```

Example:

```php

if ($cache->delete('foo3')) {
echo 'foo3 has been deleted successfully.';
} else {
echo 'Failed to delete key foo3.';
}
// foo3 has been deleted successfully.

if ($cache->has('foo3')) {
echo 'foo3 exists.';
} else {
echo 'foo3 does not exist.';
}
// foo3 does not exist.
```

### setMultiple

```php
public function setMultiple(iterable $values, $ttl = null): bool
```

Note that **$ttl** accepts `null`,`int`,`DateInterval`.
The `null` means that the key never expires until deleted.

Example:

```php
$array = [
'bar' => 'foo',
'bar2' => 'foo2',
];

$cache->setMultiple($array, 300);
```

### getMultiple

```php
public function getMultiple(array $keys, mixed $default = null): iterable
```

Example:

```php
$example = $cache->getMultiple(['bar', 'bar2', 'bar3'], 'hello');
var_dump($example);
/*
array(3) {
["bar"]=>
string(3) "foo"
["bar2"]=>
string(4) "foo2"
["bar3"]=>
string(5) "hello"
}
*/
```

### deleteMultiple

```php
public function deleteMultiple(array $keys): bool
```

Example:

```php
if ($cache->deleteMultiple(['bar', 'bar2'])) {
echo 'bar and bar2 have been deleted successfully.';
} else {
echo 'Failed to delete keys bar or bar2.';
}
// bar and bar2 have been deleted successfully.

$example = $cache->getMultiple(['bar', 'bar2', 'bar3'], 'hello');
var_dump($example);
/*
array(3) {
["bar"]=>
string(5) "hello"
["bar2"]=>
string(5) "hello"
["bar3"]=>
string(5) "hello"
}
*/
```

### clear

```php
public function clear(): bool
```

Example:

```php
if ($cache->clear()) {
echo 'All cached data has been deleted successfully.';
} else {
echo 'Failed to delete the cached data.';
}
// All cached data has been deleted successfully.
```

### clearExpiredItems `Non-PSR-16`

```php
public function clearExpiredItems(): array
```

This method returns a list of deleted cache keys.

*Note*: **Redis** and **Memcache**, **Memcached** drivers will always return an empty array. See *Garbage Collection* section below.

Example:

```php
$cache->set('foo', 'bar', 300);
$cache->set('foo2', 'bar2', 5);
$cache->set('foo3', 'bar3', 5);

sleep(6);

$expiredItems = $cache->clearExpiredItems();
var_dump($expiredItems);

/*
array(2) {
[0]=>
string(4) "foo2"
[1]=>
string(4) "foo3"
}
*/
```

---

## Build Data Schema

The data schema needs to be built for the initial use of MySQL and SQLite drivers.

This API can be utilized for this purpose.

```php
$cache->rebuild();
```

Or build it manually.

### MySQL

```sql
CREATE TABLE IF NOT EXISTS `cache_data` (
`cache_key` varchar(40) NOT NULL,
`cache_value` longtext,
PRIMARY KEY (`cache_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

### SQLite

```sql
CREATE TABLE IF NOT EXISTS cache_data (
cache_key VARCHAR(40) PRIMARY KEY,
cache_value LONGTEXT
);
```

---

## Garbage Collection

For built-in drivers, enabling garbage collection will automatically clear expired cache from your system.

Use the following parameters:

```php
$config = [
'gc_enable' => true,
'gc_divisor' => 100, // default
'gc_probability' => 1, // default
];
```

This implies a 1% probability of executing garbage collection.
Avoid setting it to 100% as it will unnecessarily fetch and check all keys one by one.

Example:
```php
$driver = new \Shieldon\SimpleCache\Cache('file', [
'storage' => __DIR__ . '/../tmp',
'gc_enable' => true,
]);
```

You can just use the `gc_enable` to enable garbage collection.

### Note

For the **Redis**, **Memcache**, and **Memcached** drivers, this method isn't necessary as expired items are automatically cleared.

---

## Contributing

Thank you for your interest in contributing to our project! We welcome contributions from everyone. Before getting started, please take a moment to review the guidelines below:

### Guidelines

- Fork the repository and create your branch from master.
- Make sure your code follows our coding style and conventions.
- Keep your code concise, well-documented, and modular.
- Write clear commit messages that describe the purpose of your changes.
- Test your changes thoroughly to ensure they don't introduce any new issues.
- Make sure your code builds successfully without any errors or warnings.
- Update relevant documentation, including README files if necessary.
- Submit a pull request (PR) to the master branch of the original repository.

### Code Testing

We utilize a Docker image that includes various dependencies for our code testing. The image is based on `/tests/Fixture/docker/Dockerfile` and is preconfigured with the following components:

- Redis
- MongoDB
- MySQL
- PHP
- Memcached
- APCu

Follow the steps below to run the tests:

- Make sure you have Docker installed on your machine. If not, you can download and install it from the official Docker website.
- Navigate to the project directory and build the Docker image by running the following command:
```
composer test:docker:build
```
- Once the Docker image is built, you can run the tests by executing the following command:
```
composer test:docker:run
```
- Observe the test results and make note of any failures or errors. The output will be displayed in the terminal.

---

## Author

- [Terry L.](https://terryl.in/) and contributers, such as [Jimmy](https://colocal.com) and others.

#### The Origin of this Library

This PHP library was created for the [12th Ironman Game](https://ithelp.ithome.com.tw/2020-12th-ironman) competition, hosted by ITHelp, a Taiwanese IT community. My chosen topic was "Road to PHP Master - The Best Practice in Open Source Code", composed in traditional Chinese. You can read it [here](https://ithelp.ithome.com.tw/users/20111119/ironman/3269) if you're interested.

## License

MIT