Nette Documentation Preview

syntax
Caching
*******

<div class=perex>

Η κρυφή μνήμη επιταχύνει την εφαρμογή σας αποθηκεύοντας δεδομένα - αφού ανακτηθούν με δυσκολία - για μελλοντική χρήση. Θα σας δείξουμε:

- Πώς να χρησιμοποιήσετε την κρυφή μνήμη
- Πώς να αλλάξετε την αποθήκευση της κρυφής μνήμης
- Πώς να ακυρώνετε σωστά την κρυφή μνήμη

</div>

Η χρήση της κρυφής μνήμης είναι πολύ εύκολη στη Nette, ενώ καλύπτει και πολύ προχωρημένες ανάγκες κρυφής μνήμης. Είναι σχεδιασμένη για απόδοση και 100% ανθεκτικότητα. Βασικά, θα βρείτε προσαρμογείς για τους πιο συνηθισμένους backend αποθηκευτικούς χώρους. Επιτρέπει την ακύρωση με βάση τις ετικέτες, την προστασία από το stampede της κρυφής μνήμης, τη χρονική λήξη κ.λπ.


Εγκατάσταση .[#toc-installation]
================================

Κατεβάστε και εγκαταστήστε το πακέτο χρησιμοποιώντας το [Composer |best-practices:composer]:

```shell
composer require nette/caching
```


Βασική χρήση .[#toc-basic-usage]
================================

Το κέντρο της εργασίας με την κρυφή μνήμη είναι το αντικείμενο [api:Nette\Caching\Cache]. Δημιουργούμε την εμφάνισή του και παραδίδουμε στον κατασκευαστή ως παράμετρο τη λεγόμενη αποθήκευση. Το οποίο είναι ένα αντικείμενο που αντιπροσωπεύει το μέρος όπου θα αποθηκευτούν φυσικά τα δεδομένα (βάση δεδομένων, Memcached, αρχεία στο δίσκο, ...). Παίρνετε το αντικείμενο storage περνώντας το χρησιμοποιώντας [dependency injection |dependency-injection:passing-dependencies] με τύπο `Nette\Caching\Storage`. Θα μάθετε όλα τα βασικά στοιχεία στην [ενότητα Storage (Αποθήκευση |#Storages]).

.[warning]
Στην έκδοση 3.0, η διεπαφή είχε ακόμα το `I` prefix, so the name was `Nette\Caching\IStorage`. Επίσης, οι σταθερές της κλάσης `Cache` γράφονταν με κεφαλαίο, έτσι για παράδειγμα `Cache::EXPIRE` αντί για `Cache::Expire`.

Για τα παρακάτω παραδείγματα, ας υποθέσουμε ότι έχουμε ένα ψευδώνυμο `Cache` και μια αποθήκευση στη μεταβλητή `$storage`.

```php
use Nette\Caching\Cache;

$storage = /* ... */; // instance of Nette\Caching\Storage
```

Η κρυφή μνήμη είναι στην πραγματικότητα ένας *αποθηκευτής κλειδιών-τιμών*, οπότε διαβάζουμε και γράφουμε δεδομένα κάτω από κλειδιά ακριβώς όπως οι συσχετιστικοί πίνακες. Οι εφαρμογές αποτελούνται από έναν αριθμό ανεξάρτητων τμημάτων, και αν όλα χρησιμοποιούσαν έναν αποθηκευτικό χώρο (για ιδέα: έναν κατάλογο σε ένα δίσκο), αργά ή γρήγορα θα υπήρχε σύγκρουση κλειδιών. Το Nette Framework λύνει το πρόβλημα χωρίζοντας ολόκληρο το χώρο σε χώρους ονομάτων (υποκαταλόγους). Κάθε μέρος του προγράμματος χρησιμοποιεί τότε τον δικό του χώρο με ένα μοναδικό όνομα και δεν μπορούν να προκύψουν συγκρούσεις.

Το όνομα του χώρου καθορίζεται ως δεύτερη παράμετρος του κατασκευαστή της κλάσης Cache:

```php
$cache = new Cache($storage, 'Full Html Pages');
```

Μπορούμε τώρα να χρησιμοποιήσουμε το αντικείμενο `$cache` για να διαβάσουμε και να γράψουμε από την κρυφή μνήμη. Η μέθοδος `load()` χρησιμοποιείται και για τα δύο. Το πρώτο όρισμα είναι το κλειδί και το δεύτερο είναι το callback της PHP, το οποίο καλείται όταν το κλειδί δεν βρεθεί στην κρυφή μνήμη. Το callback παράγει μια τιμή, την επιστρέφει και την αποθηκεύει στην προσωρινή μνήμη:

```php
$value = $cache->load($key, function () use ($key) {
	$computedValue = /* ... */; // βαριούς υπολογισμούς
	return $computedValue;
});
```

Εάν το δεύτερο όρισμα δεν έχει καθοριστεί `$value = $cache->load($key)`, επιστρέφεται το `null` εάν το στοιχείο δεν υπάρχει στην κρυφή μνήμη.

.[tip]
Το σπουδαίο είναι ότι μπορούν να αποθηκευτούν στην προσωρινή μνήμη οποιεσδήποτε σειριοποιήσιμες δομές, όχι μόνο συμβολοσειρές. Και το ίδιο ισχύει και για τα κλειδιά.

Το στοιχείο διαγράφεται από την κρυφή μνήμη χρησιμοποιώντας τη μέθοδο `remove()`:

```php
$cache->remove($key);
```

Μπορείτε επίσης να αποθηκεύσετε ένα στοιχείο στην προσωρινή μνήμη χρησιμοποιώντας τη μέθοδο `$cache->save($key, $value, array $dependencies = [])`. Ωστόσο, προτιμάται η παραπάνω μέθοδος που χρησιμοποιεί το `load()`.


Απομνημόνευση .[#toc-memoization]
=================================

Η απομνημόνευση σημαίνει την προσωρινή αποθήκευση του αποτελέσματος μιας συνάρτησης ή μεθόδου, ώστε να μπορείτε να το χρησιμοποιήσετε την επόμενη φορά αντί να υπολογίζετε το ίδιο πράγμα ξανά και ξανά.

Οι μέθοδοι και οι συναρτήσεις μπορούν να κληθούν memoized χρησιμοποιώντας το `call(callable $callback, ...$args)`:

```php
$result = $cache->call('gethostbyaddr', $ip);
```

Η συνάρτηση `gethostbyaddr()` καλείται μόνο μία φορά για κάθε παράμετρο `$ip` και την επόμενη φορά θα επιστραφεί η τιμή από την κρυφή μνήμη.

Είναι επίσης δυνατό να δημιουργηθεί ένα μνημονικό περιτύλιγμα για μια μέθοδο ή συνάρτηση που μπορεί να κληθεί αργότερα:

```php
function factorial($num)
{
	return /* ... */;
}

$memoizedFactorial = $cache->wrap('factorial');

$result = $memoizedFactorial(5); // το μετράει
$result = $memoizedFactorial(5); // το επιστρέφει από την κρυφή μνήμη
```


Λήξη & Ακύρωση .[#toc-expiration-invalidation]
==============================================

Με την προσωρινή αποθήκευση, είναι απαραίτητο να αντιμετωπιστεί το ζήτημα ότι ορισμένα από τα δεδομένα που έχουν αποθηκευτεί προηγουμένως θα καταστούν άκυρα με την πάροδο του χρόνου. Το Nette Framework παρέχει έναν μηχανισμό, με τον οποίο μπορείτε να περιορίσετε την εγκυρότητα των δεδομένων και να τα διαγράψετε με ελεγχόμενο τρόπο ("να τα ακυρώσετε", χρησιμοποιώντας την ορολογία του πλαισίου).

Η εγκυρότητα των δεδομένων ορίζεται κατά τη στιγμή της αποθήκευσης με τη χρήση της τρίτης παραμέτρου της μεθόδου `save()`, π.χ:

```php
$cache->save($key, $value, [
	$cache::Expire => '20 minutes',
]);
```

Ή με τη χρήση της παραμέτρου `$dependencies` που περνά μέσω αναφοράς στην επανάκληση της μεθόδου `load()`, π.χ:

```php
$value = $cache->load($key, function (&$dependencies) {
	$dependencies[Cache::Expire] = '20 minutes';
	return /* ... */;
});
```

Ή χρησιμοποιώντας την 3η παράμετρο στη μέθοδο `load()`, π.χ:

```php
$value = $cache->load($key, function () {
	return ...;
}, [Cache::Expire => '20 minutes']);
```

Στα παραδείγματα που ακολουθούν, θα υποθέσουμε τη δεύτερη παραλλαγή και συνεπώς την ύπαρξη μιας μεταβλητής `$dependencies`.


Λήξη .[#toc-expiration]
-----------------------

Η απλούστερη λήξη είναι το χρονικό όριο. Εδώ είναι ο τρόπος για να αποθηκεύσετε δεδομένα που ισχύουν για 20 λεπτά:

```php
// δέχεται επίσης τον αριθμό των δευτερολέπτων ή τη χρονοσφραγίδα UNIX
$dependencies[Cache::Expire] = '20 minutes';
```

Αν θέλουμε να επεκτείνουμε την περίοδο ισχύος με κάθε ανάγνωση, αυτό μπορεί να επιτευχθεί με αυτόν τον τρόπο, αλλά προσέξτε, αυτό θα αυξήσει την επιβάρυνση της κρυφής μνήμης:

```php
$dependencies[Cache::Sliding] = true;
```

Η εύχρηστη επιλογή είναι η δυνατότητα να αφήνουμε τα δεδομένα να λήγουν όταν αλλάζει ένα συγκεκριμένο αρχείο ή ένα από πολλά αρχεία. Αυτό μπορεί να χρησιμοποιηθεί, για παράδειγμα, για την προσωρινή αποθήκευση δεδομένων που προκύπτουν από την επεξεργασία αυτών των αρχείων. Χρήση απόλυτων διαδρομών.

```php
$dependencies[Cache::Files] = '/path/to/data.yaml';
// ή
$dependencies[Cache::Files] = ['/path/to/data1.yaml', '/path/to/data2.yaml'];
```

Μπορούμε να αφήσουμε ένα στοιχείο της κρυφής μνήμης να λήξει όταν λήξει ένα άλλο στοιχείο (ή ένα από πολλά άλλα). Αυτό μπορεί να χρησιμοποιηθεί όταν αποθηκεύουμε στην κρυφή μνήμη ολόκληρη τη σελίδα HTML και τμήματα αυτής κάτω από άλλα κλειδιά. Μόλις αλλάξει το απόσπασμα, ολόκληρη η σελίδα καθίσταται άκυρη. Αν έχουμε αποθηκευμένα αποσπάσματα κάτω από κλειδιά όπως `frag1` και `frag2`, θα χρησιμοποιήσουμε:

```php
$dependencies[Cache::Items] = ['frag1', 'frag2'];
```

Η λήξη μπορεί επίσης να ελεγχθεί με τη χρήση προσαρμοσμένων συναρτήσεων ή στατικών μεθόδων, οι οποίες αποφασίζουν πάντα κατά την ανάγνωση αν το στοιχείο είναι ακόμα έγκυρο. Για παράδειγμα, μπορούμε να αφήσουμε το στοιχείο να λήξει κάθε φορά που αλλάζει η έκδοση της PHP. Θα δημιουργήσουμε μια συνάρτηση που θα συγκρίνει την τρέχουσα έκδοση με την παράμετρο και κατά την αποθήκευση θα προσθέσουμε έναν πίνακα της μορφής `[function name, ...arguments]` στις εξαρτήσεις:

```php
function checkPhpVersion($ver): bool
{
	return $ver === PHP_VERSION_ID;
}

$dependencies[Cache::Callbacks] = [
	['checkPhpVersion', PHP_VERSION_ID] // λήγει όταν checkPhpVersion(...) === false
];
```

Φυσικά, όλα τα κριτήρια μπορούν να συνδυαστούν. Η κρυφή μνήμη τότε λήγει όταν δεν ικανοποιείται τουλάχιστον ένα κριτήριο.

```php
$dependencies[Cache::Expire] = '20 minutes';
$dependencies[Cache::Files] = '/path/to/data.yaml';
```


Ακύρωση με χρήση ετικετών .[#toc-invalidation-using-tags]
---------------------------------------------------------

Οι ετικέτες είναι ένα πολύ χρήσιμο εργαλείο ακύρωσης. Μπορούμε να αντιστοιχίσουμε μια λίστα ετικετών, οι οποίες είναι αυθαίρετες συμβολοσειρές, σε κάθε στοιχείο που είναι αποθηκευμένο στην κρυφή μνήμη. Για παράδειγμα, ας υποθέσουμε ότι έχουμε μια σελίδα HTML με ένα άρθρο και σχόλια, την οποία θέλουμε να αποθηκεύσουμε στην κρυφή μνήμη. Οπότε καθορίζουμε ετικέτες κατά την αποθήκευση στην κρυφή μνήμη:

```php
$dependencies[Cache::Tags] = ["article/$articleId", "comments/$articleId"];
```

Τώρα, ας προχωρήσουμε στη διαχείριση. Εδώ έχουμε μια φόρμα για την επεξεργασία άρθρων. Μαζί με την αποθήκευση του άρθρου σε μια βάση δεδομένων, καλούμε την εντολή `clean()`, η οποία θα διαγράψει τα αποθηκευμένα στοιχεία ανά ετικέτα:

```php
$cache->clean([
	$cache::Tags => ["article/$articleId"],
]);
```

Ομοίως, στη θέση της προσθήκης ενός νέου σχολίου (ή της επεξεργασίας ενός σχολίου), δεν θα ξεχάσουμε να ακυρώσουμε τη σχετική ετικέτα:

```php
$cache->clean([
	$cache::Tags => ["comments/$articleId"],
]);
```

Τι πετύχαμε; Ότι η κρυφή μνήμη HTML μας θα ακυρώνεται (διαγράφεται) κάθε φορά που το άρθρο ή τα σχόλια αλλάζουν. Κατά την επεξεργασία ενός άρθρου με ID = 10, η ετικέτα `article/10` αναγκάζεται να ακυρωθεί και η σελίδα HTML που φέρει την ετικέτα διαγράφεται από την κρυφή μνήμη. Το ίδιο συμβαίνει όταν εισάγετε ένα νέο σχόλιο κάτω από το σχετικό άρθρο.

.[note]
Οι ετικέτες απαιτούν [Journal |#Journal].


Ακύρωση κατά προτεραιότητα .[#toc-invalidation-by-priority]
-----------------------------------------------------------

Μπορούμε να ορίσουμε την προτεραιότητα για μεμονωμένα στοιχεία στην κρυφή μνήμη, και θα είναι δυνατή η διαγραφή τους με ελεγχόμενο τρόπο όταν, για παράδειγμα, η κρυφή μνήμη υπερβαίνει ένα συγκεκριμένο μέγεθος:

```php
$dependencies[Cache::Priority] = 50;
```

Διαγραφή όλων των στοιχείων με προτεραιότητα ίση ή μικρότερη από 100:

```php
$cache->clean([
	$cache::Priority => 100,
]);
```

.[note]
Οι προτεραιότητες απαιτούν το λεγόμενο [Journal |#Journal].


Εκκαθάριση προσωρινής μνήμης .[#toc-clear-cache]
------------------------------------------------

Η παράμετρος `Cache::All` καθαρίζει τα πάντα:

```php
$cache->clean([
	$cache::All => true,
]);
```


Bulk Reading .[#toc-bulk-reading]
=================================

Για μαζική ανάγνωση και εγγραφή στην κρυφή μνήμη χρησιμοποιείται η μέθοδος `bulkLoad()`, όπου περνάμε έναν πίνακα κλειδιών και λαμβάνουμε έναν πίνακα τιμών:

```php
$values = $cache->bulkLoad($keys);
```

Η μέθοδος `bulkLoad()` λειτουργεί παρόμοια με τη μέθοδο `load()` με τη δεύτερη παράμετρο επανάκλησης, στην οποία περνάει το κλειδί του παραγόμενου στοιχείου:

```php
$values = $cache->bulkLoad($keys, function ($key, &$dependencies) {
	$computedValue = /* ... */; // βαριοί υπολογισμοί
	return $computedValue;
});
```


Χρήση με PSR-16 .[#toc-using-with-psr-16]
=========================================

Για να χρησιμοποιήσετε τη Nette Cache με τη διασύνδεση PSR-16, μπορείτε να χρησιμοποιήσετε το `PsrCacheAdapter`. Επιτρέπει την απρόσκοπτη ενσωμάτωση μεταξύ της Nette Cache και οποιουδήποτε κώδικα ή βιβλιοθήκης που αναμένει μια κρυφή μνήμη συμβατή με PSR-16.

```php
$psrCache = new Nette\Bridges\Psr\PsrCacheAdapter($storage);
```

Τώρα μπορείτε να χρησιμοποιήσετε το `$psrCache` ως κρυφή μνήμη PSR-16:

```php
$psrCache->set('key', 'value', 3600); // αποθηκεύει την τιμή για 1 ώρα
$value = $psrCache->get('key', 'default');
```

Ο προσαρμογέας υποστηρίζει όλες τις μεθόδους που ορίζονται στο PSR-16, συμπεριλαμβανομένων των `getMultiple()`, `setMultiple()` και `deleteMultiple()`.


Προσωρινή αποθήκευση εξόδου .[#toc-output-caching]
==================================================

Η έξοδος μπορεί να συλληφθεί και να αποθηκευτεί στην προσωρινή μνήμη πολύ κομψά:

```php
if ($capture = $cache->capture($key)) {

	echo ... // εκτύπωση ορισμένων δεδομένων

	$capture->end(); // αποθήκευση της εξόδου στην κρυφή μνήμη
}
```

Σε περίπτωση που η έξοδος υπάρχει ήδη στην κρυφή μνήμη, η μέθοδος `capture()` την εκτυπώνει και επιστρέφει `null`, οπότε η συνθήκη δεν θα εκτελεστεί. Διαφορετικά, αρχίζει να αποθηκεύει την έξοδο και επιστρέφει το αντικείμενο `$capture` με το οποίο τελικά αποθηκεύουμε τα δεδομένα στην κρυφή μνήμη.

.[note]
Στην έκδοση 3.0 η μέθοδος ονομαζόταν `$cache->start()`.


Προσωρινή αποθήκευση στο Latte .[#toc-caching-in-latte]
=======================================================

Η προσωρινή αποθήκευση σε πρότυπα [Latte |latte:] είναι πολύ εύκολη, απλά τυλίξτε μέρος του προτύπου με ετικέτες `{cache}...{/cache}`. Η προσωρινή αποθήκευση ακυρώνεται αυτόματα όταν αλλάζει το πηγαίο πρότυπο (συμπεριλαμβανομένων τυχόν περιεχόμενων προτύπων μέσα στις ετικέτες `{cache}` ). Οι ετικέτες `{cache}` μπορούν να είναι φωλιασμένες, και όταν ένα φωλιασμένο μπλοκ ακυρώνεται (για παράδειγμα, από μια ετικέτα), το γονικό μπλοκ ακυρώνεται επίσης.

Στην ετικέτα είναι δυνατόν να καθοριστούν τα κλειδιά στα οποία θα δεσμεύεται η κρυφή μνήμη (εδώ η μεταβλητή `$id`) και να οριστούν οι ετικέτες λήξης και [ακύρωσης |#Invalidation using Tags]

```latte
{cache $id, expire: '20 minutes', tags: [tag1, tag2]}
	...
{/cache}
```

Όλες οι παράμετροι είναι προαιρετικές, οπότε δεν χρειάζεται να καθορίσετε τη λήξη, τις ετικέτες ή τα κλειδιά.

Η χρήση της κρυφής μνήμης μπορεί επίσης να εξαρτάται από τη διεύθυνση `if` - το περιεχόμενο θα αποθηκευτεί στην κρυφή μνήμη μόνο εάν πληρούται η συνθήκη:

```latte
{cache $id, if: !$form->isSubmitted()}
	{$form}
{/cache}
```


Αποθήκες .[#toc-storages]
=========================

Ένας αποθηκευτικός χώρος είναι ένα αντικείμενο που αντιπροσωπεύει τον τόπο όπου αποθηκεύονται φυσικά τα δεδομένα. Μπορούμε να χρησιμοποιήσουμε μια βάση δεδομένων, έναν διακομιστή Memcached ή τον πιο διαθέσιμο αποθηκευτικό χώρο, που είναι τα αρχεία στο δίσκο.

|----------------------
| Αποθήκευση | Περιγραφή
|----------------------
| [FileStorage |#FileStorage] | προεπιλεγμένη αποθήκευση με αποθήκευση σε αρχεία στο δίσκο
| [MemcachedStorage |#MemcachedStorage] | χρησιμοποιεί τον διακομιστή `Memcached`
| [MemoryStorage |#MemoryStorage] | τα δεδομένα βρίσκονται προσωρινά στη μνήμη
| [SQLiteStorage |#SQLiteStorage] | τα δεδομένα αποθηκεύονται σε βάση δεδομένων SQLite
| [DevNullStorage |#DevNullStorage] | τα δεδομένα δεν αποθηκεύονται - για δοκιμαστικούς σκοπούς

Λαμβάνετε το αντικείμενο αποθήκευσης περνώντας το χρησιμοποιώντας [dependency injection |dependency-injection:passing-dependencies] με τον τύπο `Nette\Caching\Storage`. Από προεπιλογή, η Nette παρέχει ένα αντικείμενο FileStorage που αποθηκεύει δεδομένα σε έναν υποφάκελο `cache` στον κατάλογο για [προσωρινά αρχεία |application:bootstrap#Temporary Files].

Μπορείτε να αλλάξετε την αποθήκευση στη διαμόρφωση:

```neon
services:
	cache.storage: Nette\Caching\Storages\DevNullStorage
```


FileStorage .[#toc-filestorage]
-------------------------------

Γράφει την κρυφή μνήμη σε αρχεία στο δίσκο. Η αποθήκευση `Nette\Caching\Storages\FileStorage` είναι πολύ καλά βελτιστοποιημένη για την απόδοση και πάνω απ' όλα εξασφαλίζει πλήρη ατομικότητα των λειτουργιών. Τι σημαίνει αυτό; Ότι κατά τη χρήση της κρυφής μνήμης δεν μπορεί να συμβεί να διαβάσουμε ένα αρχείο που δεν έχει ακόμα γραφτεί πλήρως από κάποιο άλλο νήμα ή να το διαγράψει κάποιος "κάτω από τα χέρια σας". Η χρήση της κρυφής μνήμης είναι επομένως απολύτως ασφαλής.

Αυτή η αποθήκευση έχει επίσης ένα σημαντικό ενσωματωμένο χαρακτηριστικό που αποτρέπει την ακραία αύξηση της χρήσης της CPU όταν η κρυφή μνήμη διαγράφεται ή ψύχεται (δηλαδή δεν δημιουργείται). Αυτή είναι η πρόληψη "stampede cache":https://en.wikipedia.org/wiki/Cache_stampede.
Συμβαίνει ότι σε μια στιγμή υπάρχουν πολλές ταυτόχρονες αιτήσεις που θέλουν το ίδιο πράγμα από την κρυφή μνήμη (π.χ. το αποτέλεσμα ενός ακριβού ερωτήματος SQL) και επειδή αυτό δεν έχει αποθηκευτεί στην κρυφή μνήμη, όλες οι διεργασίες αρχίζουν να εκτελούν το ίδιο ερώτημα SQL.
Το φορτίο του επεξεργαστή πολλαπλασιάζεται και μπορεί να συμβεί ακόμη και να μην μπορεί κανένα νήμα να ανταποκριθεί εντός του χρονικού ορίου, να μη δημιουργηθεί η κρυφή μνήμη και να καταρρεύσει η εφαρμογή.
Ευτυχώς, η κρυφή μνήμη στο Nette λειτουργεί με τέτοιο τρόπο ώστε όταν υπάρχουν πολλαπλές ταυτόχρονες αιτήσεις για ένα στοιχείο, αυτό δημιουργείται μόνο από το πρώτο νήμα, τα υπόλοιπα περιμένουν και στη συνέχεια χρησιμοποιούν το παραγόμενο αποτέλεσμα.

Παράδειγμα δημιουργίας ενός FileStorage:

```php
// η αποθήκευση θα είναι ο κατάλογος '/path/to/temp' στο δίσκο
$storage = new Nette\Caching\Storages\FileStorage('/path/to/temp');
```


MemcachedStorage .[#toc-memcachedstorage]
-----------------------------------------

Ο διακομιστής [Memcached |https://memcached.org] είναι ένα κατανεμημένο σύστημα αποθήκευσης υψηλής απόδοσης, του οποίου ο προσαρμογέας είναι `Nette\Caching\Storages\MemcachedStorage`. Στη διαμόρφωση, καθορίστε τη διεύθυνση IP και τη θύρα, εάν διαφέρουν από το πρότυπο 11211.

.[caution]
Απαιτεί την επέκταση PHP `memcached`.

```neon
services:
	cache.storage: Nette\Caching\Storages\MemcachedStorage('10.0.0.5')
```


MemoryStorage .[#toc-memorystorage]
-----------------------------------

`Nette\Caching\Storages\MemoryStorage` είναι ένας αποθηκευτικός χώρος που αποθηκεύει δεδομένα σε έναν πίνακα PHP και έτσι χάνονται όταν τερματιστεί η αίτηση.


SQLiteStorage .[#toc-sqlitestorage]
-----------------------------------

Η βάση δεδομένων SQLite και ο προσαρμογέας `Nette\Caching\Storages\SQLiteStorage` προσφέρουν έναν τρόπο προσωρινής αποθήκευσης σε ένα μόνο αρχείο στο δίσκο. Η ρύθμιση παραμέτρων θα καθορίσει τη διαδρομή προς αυτό το αρχείο.

.[caution]
Απαιτεί τις επεκτάσεις PHP `pdo` και `pdo_sqlite`.

```neon
services:
	cache.storage: Nette\Caching\Storages\SQLiteStorage('%tempDir%/cache.db')
```


DevNullStorage .[#toc-devnullstorage]
-------------------------------------

Μια ειδική υλοποίηση της αποθήκευσης είναι η `Nette\Caching\Storages\DevNullStorage`, η οποία στην πραγματικότητα δεν αποθηκεύει καθόλου δεδομένα. Επομένως, είναι κατάλληλη για δοκιμές αν θέλουμε να εξαλείψουμε την επίδραση της κρυφής μνήμης.


Χρήση της κρυφής μνήμης στον κώδικα .[#toc-using-cache-in-code]
===============================================================

Όταν χρησιμοποιείτε προσωρινή αποθήκευση στον κώδικα, έχετε δύο τρόπους για να το κάνετε. Ο πρώτος είναι ότι παίρνετε το αντικείμενο αποθήκευσης περνώντας το με τη χρήση [dependency injection |dependency-injection:passing-dependencies] και στη συνέχεια δημιουργείτε ένα αντικείμενο `Cache`:

```php
use Nette;

class ClassOne
{
	private Nette\Caching\Cache $cache;

	public function __construct(Nette\Caching\Storage $storage)
	{
		$this->cache = new Nette\Caching\Cache($storage, 'my-namespace');
	}
}
```

Ο δεύτερος τρόπος είναι ότι παίρνετε το αντικείμενο αποθήκευσης `Cache`:

```php
class ClassTwo
{
	public function __construct(
		private Nette\Caching\Cache $cache,
	) {
	}
}
```

Το αντικείμενο `Cache` δημιουργείται στη συνέχεια απευθείας στη διαμόρφωση ως εξής:

```neon
services:
	- ClassTwo( Nette\Caching\Cache(namespace: 'my-namespace') )
```


Περιοδικό .[#toc-journal]
=========================

Η Nette αποθηκεύει ετικέτες και προτεραιότητες σε ένα λεγόμενο ημερολόγιο. Από προεπιλογή, χρησιμοποιείται το SQLite και το αρχείο `journal.s3db` γι' αυτό, ενώ απαιτούνται οι επεκτάσεις **PHP `pdo` και `pdo_sqlite`. **

Μπορείτε να αλλάξετε το ημερολόγιο στη διαμόρφωση:

```neon
services:
	cache.journal: MyJournal
```


Υπηρεσίες DI .[#toc-di-services]
================================

Αυτές οι υπηρεσίες προστίθενται στο δοχείο DI:

| Όνομα | Τύπος | Περιγραφή
|----------------------------------------------------------
| `cache.journal` | [api:Nette\Caching\Storages\Journal] | journal
| `cache.storage` | [api:Nette\Caching\Storage] | repository


Απενεργοποίηση της κρυφής μνήμης .[#toc-turning-off-cache]
==========================================================

Ένας από τους τρόπους για να απενεργοποιήσετε την προσωρινή αποθήκευση στην εφαρμογή είναι να ορίσετε τον αποθηκευτικό χώρο σε [DevNullStorage |#DevNullStorage]:

```neon
services:
	cache.storage: Nette\Caching\Storages\DevNullStorage
```

Αυτή η ρύθμιση δεν επηρεάζει την προσωρινή αποθήκευση των προτύπων στο Latte ή στο DI container, καθώς αυτές οι βιβλιοθήκες δεν χρησιμοποιούν τις υπηρεσίες της nette/caching και διαχειρίζονται την προσωρινή τους μνήμη ανεξάρτητα. Επιπλέον, η κρυφή μνήμη τους [δεν χρειάζεται να απ |nette:troubleshooting#how-to-disable-cache-during-development] ενεργοποιηθεί στη λειτουργία ανάπτυξης.


{{leftbar: nette:@menu-topics}}

Caching

Η κρυφή μνήμη επιταχύνει την εφαρμογή σας αποθηκεύοντας δεδομένα – αφού ανακτηθούν με δυσκολία – για μελλοντική χρήση. Θα σας δείξουμε:

  • Πώς να χρησιμοποιήσετε την κρυφή μνήμη
  • Πώς να αλλάξετε την αποθήκευση της κρυφής μνήμης
  • Πώς να ακυρώνετε σωστά την κρυφή μνήμη

Η χρήση της κρυφής μνήμης είναι πολύ εύκολη στη Nette, ενώ καλύπτει και πολύ προχωρημένες ανάγκες κρυφής μνήμης. Είναι σχεδιασμένη για απόδοση και 100% ανθεκτικότητα. Βασικά, θα βρείτε προσαρμογείς για τους πιο συνηθισμένους backend αποθηκευτικούς χώρους. Επιτρέπει την ακύρωση με βάση τις ετικέτες, την προστασία από το stampede της κρυφής μνήμης, τη χρονική λήξη κ.λπ.

Εγκατάσταση

Κατεβάστε και εγκαταστήστε το πακέτο χρησιμοποιώντας το Composer:

composer require nette/caching

Βασική χρήση

Το κέντρο της εργασίας με την κρυφή μνήμη είναι το αντικείμενο Nette\Caching\Cache. Δημιουργούμε την εμφάνισή του και παραδίδουμε στον κατασκευαστή ως παράμετρο τη λεγόμενη αποθήκευση. Το οποίο είναι ένα αντικείμενο που αντιπροσωπεύει το μέρος όπου θα αποθηκευτούν φυσικά τα δεδομένα (βάση δεδομένων, Memcached, αρχεία στο δίσκο, …). Παίρνετε το αντικείμενο storage περνώντας το χρησιμοποιώντας dependency injection με τύπο Nette\Caching\Storage. Θα μάθετε όλα τα βασικά στοιχεία στην ενότητα Storage (Αποθήκευση).

Στην έκδοση 3.0, η διεπαφή είχε ακόμα το I prefix, so the name was Nette\Caching\IStorage. Επίσης, οι σταθερές της κλάσης Cache γράφονταν με κεφαλαίο, έτσι για παράδειγμα Cache::EXPIRE αντί για Cache::Expire.

Για τα παρακάτω παραδείγματα, ας υποθέσουμε ότι έχουμε ένα ψευδώνυμο Cache και μια αποθήκευση στη μεταβλητή $storage.

use Nette\Caching\Cache;

$storage = /* ... */; // instance of Nette\Caching\Storage

Η κρυφή μνήμη είναι στην πραγματικότητα ένας αποθηκευτής κλειδιών-τιμών, οπότε διαβάζουμε και γράφουμε δεδομένα κάτω από κλειδιά ακριβώς όπως οι συσχετιστικοί πίνακες. Οι εφαρμογές αποτελούνται από έναν αριθμό ανεξάρτητων τμημάτων, και αν όλα χρησιμοποιούσαν έναν αποθηκευτικό χώρο (για ιδέα: έναν κατάλογο σε ένα δίσκο), αργά ή γρήγορα θα υπήρχε σύγκρουση κλειδιών. Το Nette Framework λύνει το πρόβλημα χωρίζοντας ολόκληρο το χώρο σε χώρους ονομάτων (υποκαταλόγους). Κάθε μέρος του προγράμματος χρησιμοποιεί τότε τον δικό του χώρο με ένα μοναδικό όνομα και δεν μπορούν να προκύψουν συγκρούσεις.

Το όνομα του χώρου καθορίζεται ως δεύτερη παράμετρος του κατασκευαστή της κλάσης Cache:

$cache = new Cache($storage, 'Full Html Pages');

Μπορούμε τώρα να χρησιμοποιήσουμε το αντικείμενο $cache για να διαβάσουμε και να γράψουμε από την κρυφή μνήμη. Η μέθοδος load() χρησιμοποιείται και για τα δύο. Το πρώτο όρισμα είναι το κλειδί και το δεύτερο είναι το callback της PHP, το οποίο καλείται όταν το κλειδί δεν βρεθεί στην κρυφή μνήμη. Το callback παράγει μια τιμή, την επιστρέφει και την αποθηκεύει στην προσωρινή μνήμη:

$value = $cache->load($key, function () use ($key) {
	$computedValue = /* ... */; // βαριούς υπολογισμούς
	return $computedValue;
});

Εάν το δεύτερο όρισμα δεν έχει καθοριστεί $value = $cache->load($key), επιστρέφεται το null εάν το στοιχείο δεν υπάρχει στην κρυφή μνήμη.

Το σπουδαίο είναι ότι μπορούν να αποθηκευτούν στην προσωρινή μνήμη οποιεσδήποτε σειριοποιήσιμες δομές, όχι μόνο συμβολοσειρές. Και το ίδιο ισχύει και για τα κλειδιά.

Το στοιχείο διαγράφεται από την κρυφή μνήμη χρησιμοποιώντας τη μέθοδο remove():

$cache->remove($key);

Μπορείτε επίσης να αποθηκεύσετε ένα στοιχείο στην προσωρινή μνήμη χρησιμοποιώντας τη μέθοδο $cache->save($key, $value, array $dependencies = []). Ωστόσο, προτιμάται η παραπάνω μέθοδος που χρησιμοποιεί το load().

Απομνημόνευση

Η απομνημόνευση σημαίνει την προσωρινή αποθήκευση του αποτελέσματος μιας συνάρτησης ή μεθόδου, ώστε να μπορείτε να το χρησιμοποιήσετε την επόμενη φορά αντί να υπολογίζετε το ίδιο πράγμα ξανά και ξανά.

Οι μέθοδοι και οι συναρτήσεις μπορούν να κληθούν memoized χρησιμοποιώντας το call(callable $callback, ...$args):

$result = $cache->call('gethostbyaddr', $ip);

Η συνάρτηση gethostbyaddr() καλείται μόνο μία φορά για κάθε παράμετρο $ip και την επόμενη φορά θα επιστραφεί η τιμή από την κρυφή μνήμη.

Είναι επίσης δυνατό να δημιουργηθεί ένα μνημονικό περιτύλιγμα για μια μέθοδο ή συνάρτηση που μπορεί να κληθεί αργότερα:

function factorial($num)
{
	return /* ... */;
}

$memoizedFactorial = $cache->wrap('factorial');

$result = $memoizedFactorial(5); // το μετράει
$result = $memoizedFactorial(5); // το επιστρέφει από την κρυφή μνήμη

Λήξη & Ακύρωση

Με την προσωρινή αποθήκευση, είναι απαραίτητο να αντιμετωπιστεί το ζήτημα ότι ορισμένα από τα δεδομένα που έχουν αποθηκευτεί προηγουμένως θα καταστούν άκυρα με την πάροδο του χρόνου. Το Nette Framework παρέχει έναν μηχανισμό, με τον οποίο μπορείτε να περιορίσετε την εγκυρότητα των δεδομένων και να τα διαγράψετε με ελεγχόμενο τρόπο („να τα ακυρώσετε“, χρησιμοποιώντας την ορολογία του πλαισίου).

Η εγκυρότητα των δεδομένων ορίζεται κατά τη στιγμή της αποθήκευσης με τη χρήση της τρίτης παραμέτρου της μεθόδου save(), π.χ:

$cache->save($key, $value, [
	$cache::Expire => '20 minutes',
]);

Ή με τη χρήση της παραμέτρου $dependencies που περνά μέσω αναφοράς στην επανάκληση της μεθόδου load(), π.χ:

$value = $cache->load($key, function (&$dependencies) {
	$dependencies[Cache::Expire] = '20 minutes';
	return /* ... */;
});

Ή χρησιμοποιώντας την 3η παράμετρο στη μέθοδο load(), π.χ:

$value = $cache->load($key, function () {
	return ...;
}, [Cache::Expire => '20 minutes']);

Στα παραδείγματα που ακολουθούν, θα υποθέσουμε τη δεύτερη παραλλαγή και συνεπώς την ύπαρξη μιας μεταβλητής $dependencies.

Λήξη

Η απλούστερη λήξη είναι το χρονικό όριο. Εδώ είναι ο τρόπος για να αποθηκεύσετε δεδομένα που ισχύουν για 20 λεπτά:

// δέχεται επίσης τον αριθμό των δευτερολέπτων ή τη χρονοσφραγίδα UNIX
$dependencies[Cache::Expire] = '20 minutes';

Αν θέλουμε να επεκτείνουμε την περίοδο ισχύος με κάθε ανάγνωση, αυτό μπορεί να επιτευχθεί με αυτόν τον τρόπο, αλλά προσέξτε, αυτό θα αυξήσει την επιβάρυνση της κρυφής μνήμης:

$dependencies[Cache::Sliding] = true;

Η εύχρηστη επιλογή είναι η δυνατότητα να αφήνουμε τα δεδομένα να λήγουν όταν αλλάζει ένα συγκεκριμένο αρχείο ή ένα από πολλά αρχεία. Αυτό μπορεί να χρησιμοποιηθεί, για παράδειγμα, για την προσωρινή αποθήκευση δεδομένων που προκύπτουν από την επεξεργασία αυτών των αρχείων. Χρήση απόλυτων διαδρομών.

$dependencies[Cache::Files] = '/path/to/data.yaml';
// ή
$dependencies[Cache::Files] = ['/path/to/data1.yaml', '/path/to/data2.yaml'];

Μπορούμε να αφήσουμε ένα στοιχείο της κρυφής μνήμης να λήξει όταν λήξει ένα άλλο στοιχείο (ή ένα από πολλά άλλα). Αυτό μπορεί να χρησιμοποιηθεί όταν αποθηκεύουμε στην κρυφή μνήμη ολόκληρη τη σελίδα HTML και τμήματα αυτής κάτω από άλλα κλειδιά. Μόλις αλλάξει το απόσπασμα, ολόκληρη η σελίδα καθίσταται άκυρη. Αν έχουμε αποθηκευμένα αποσπάσματα κάτω από κλειδιά όπως frag1 και frag2, θα χρησιμοποιήσουμε:

$dependencies[Cache::Items] = ['frag1', 'frag2'];

Η λήξη μπορεί επίσης να ελεγχθεί με τη χρήση προσαρμοσμένων συναρτήσεων ή στατικών μεθόδων, οι οποίες αποφασίζουν πάντα κατά την ανάγνωση αν το στοιχείο είναι ακόμα έγκυρο. Για παράδειγμα, μπορούμε να αφήσουμε το στοιχείο να λήξει κάθε φορά που αλλάζει η έκδοση της PHP. Θα δημιουργήσουμε μια συνάρτηση που θα συγκρίνει την τρέχουσα έκδοση με την παράμετρο και κατά την αποθήκευση θα προσθέσουμε έναν πίνακα της μορφής [function name, ...arguments] στις εξαρτήσεις:

function checkPhpVersion($ver): bool
{
	return $ver === PHP_VERSION_ID;
}

$dependencies[Cache::Callbacks] = [
	['checkPhpVersion', PHP_VERSION_ID] // λήγει όταν checkPhpVersion(...) === false
];

Φυσικά, όλα τα κριτήρια μπορούν να συνδυαστούν. Η κρυφή μνήμη τότε λήγει όταν δεν ικανοποιείται τουλάχιστον ένα κριτήριο.

$dependencies[Cache::Expire] = '20 minutes';
$dependencies[Cache::Files] = '/path/to/data.yaml';

Ακύρωση με χρήση ετικετών

Οι ετικέτες είναι ένα πολύ χρήσιμο εργαλείο ακύρωσης. Μπορούμε να αντιστοιχίσουμε μια λίστα ετικετών, οι οποίες είναι αυθαίρετες συμβολοσειρές, σε κάθε στοιχείο που είναι αποθηκευμένο στην κρυφή μνήμη. Για παράδειγμα, ας υποθέσουμε ότι έχουμε μια σελίδα HTML με ένα άρθρο και σχόλια, την οποία θέλουμε να αποθηκεύσουμε στην κρυφή μνήμη. Οπότε καθορίζουμε ετικέτες κατά την αποθήκευση στην κρυφή μνήμη:

$dependencies[Cache::Tags] = ["article/$articleId", "comments/$articleId"];

Τώρα, ας προχωρήσουμε στη διαχείριση. Εδώ έχουμε μια φόρμα για την επεξεργασία άρθρων. Μαζί με την αποθήκευση του άρθρου σε μια βάση δεδομένων, καλούμε την εντολή clean(), η οποία θα διαγράψει τα αποθηκευμένα στοιχεία ανά ετικέτα:

$cache->clean([
	$cache::Tags => ["article/$articleId"],
]);

Ομοίως, στη θέση της προσθήκης ενός νέου σχολίου (ή της επεξεργασίας ενός σχολίου), δεν θα ξεχάσουμε να ακυρώσουμε τη σχετική ετικέτα:

$cache->clean([
	$cache::Tags => ["comments/$articleId"],
]);

Τι πετύχαμε; Ότι η κρυφή μνήμη HTML μας θα ακυρώνεται (διαγράφεται) κάθε φορά που το άρθρο ή τα σχόλια αλλάζουν. Κατά την επεξεργασία ενός άρθρου με ID = 10, η ετικέτα article/10 αναγκάζεται να ακυρωθεί και η σελίδα HTML που φέρει την ετικέτα διαγράφεται από την κρυφή μνήμη. Το ίδιο συμβαίνει όταν εισάγετε ένα νέο σχόλιο κάτω από το σχετικό άρθρο.

Οι ετικέτες απαιτούν Journal.

Ακύρωση κατά προτεραιότητα

Μπορούμε να ορίσουμε την προτεραιότητα για μεμονωμένα στοιχεία στην κρυφή μνήμη, και θα είναι δυνατή η διαγραφή τους με ελεγχόμενο τρόπο όταν, για παράδειγμα, η κρυφή μνήμη υπερβαίνει ένα συγκεκριμένο μέγεθος:

$dependencies[Cache::Priority] = 50;

Διαγραφή όλων των στοιχείων με προτεραιότητα ίση ή μικρότερη από 100:

$cache->clean([
	$cache::Priority => 100,
]);

Οι προτεραιότητες απαιτούν το λεγόμενο Journal.

Εκκαθάριση προσωρινής μνήμης

Η παράμετρος Cache::All καθαρίζει τα πάντα:

$cache->clean([
	$cache::All => true,
]);

Bulk Reading

Για μαζική ανάγνωση και εγγραφή στην κρυφή μνήμη χρησιμοποιείται η μέθοδος bulkLoad(), όπου περνάμε έναν πίνακα κλειδιών και λαμβάνουμε έναν πίνακα τιμών:

$values = $cache->bulkLoad($keys);

Η μέθοδος bulkLoad() λειτουργεί παρόμοια με τη μέθοδο load() με τη δεύτερη παράμετρο επανάκλησης, στην οποία περνάει το κλειδί του παραγόμενου στοιχείου:

$values = $cache->bulkLoad($keys, function ($key, &$dependencies) {
	$computedValue = /* ... */; // βαριοί υπολογισμοί
	return $computedValue;
});

Χρήση με PSR-16

Για να χρησιμοποιήσετε τη Nette Cache με τη διασύνδεση PSR-16, μπορείτε να χρησιμοποιήσετε το PsrCacheAdapter. Επιτρέπει την απρόσκοπτη ενσωμάτωση μεταξύ της Nette Cache και οποιουδήποτε κώδικα ή βιβλιοθήκης που αναμένει μια κρυφή μνήμη συμβατή με PSR-16.

$psrCache = new Nette\Bridges\Psr\PsrCacheAdapter($storage);

Τώρα μπορείτε να χρησιμοποιήσετε το $psrCache ως κρυφή μνήμη PSR-16:

$psrCache->set('key', 'value', 3600); // αποθηκεύει την τιμή για 1 ώρα
$value = $psrCache->get('key', 'default');

Ο προσαρμογέας υποστηρίζει όλες τις μεθόδους που ορίζονται στο PSR-16, συμπεριλαμβανομένων των getMultiple(), setMultiple() και deleteMultiple().

Προσωρινή αποθήκευση εξόδου

Η έξοδος μπορεί να συλληφθεί και να αποθηκευτεί στην προσωρινή μνήμη πολύ κομψά:

if ($capture = $cache->capture($key)) {

	echo ... // εκτύπωση ορισμένων δεδομένων

	$capture->end(); // αποθήκευση της εξόδου στην κρυφή μνήμη
}

Σε περίπτωση που η έξοδος υπάρχει ήδη στην κρυφή μνήμη, η μέθοδος capture() την εκτυπώνει και επιστρέφει null, οπότε η συνθήκη δεν θα εκτελεστεί. Διαφορετικά, αρχίζει να αποθηκεύει την έξοδο και επιστρέφει το αντικείμενο $capture με το οποίο τελικά αποθηκεύουμε τα δεδομένα στην κρυφή μνήμη.

Στην έκδοση 3.0 η μέθοδος ονομαζόταν $cache->start().

Προσωρινή αποθήκευση στο Latte

Η προσωρινή αποθήκευση σε πρότυπα Latte είναι πολύ εύκολη, απλά τυλίξτε μέρος του προτύπου με ετικέτες {cache}...{/cache}. Η προσωρινή αποθήκευση ακυρώνεται αυτόματα όταν αλλάζει το πηγαίο πρότυπο (συμπεριλαμβανομένων τυχόν περιεχόμενων προτύπων μέσα στις ετικέτες {cache} ). Οι ετικέτες {cache} μπορούν να είναι φωλιασμένες, και όταν ένα φωλιασμένο μπλοκ ακυρώνεται (για παράδειγμα, από μια ετικέτα), το γονικό μπλοκ ακυρώνεται επίσης.

Στην ετικέτα είναι δυνατόν να καθοριστούν τα κλειδιά στα οποία θα δεσμεύεται η κρυφή μνήμη (εδώ η μεταβλητή $id) και να οριστούν οι ετικέτες λήξης και ακύρωσης

{cache $id, expire: '20 minutes', tags: [tag1, tag2]}
	...
{/cache}

Όλες οι παράμετροι είναι προαιρετικές, οπότε δεν χρειάζεται να καθορίσετε τη λήξη, τις ετικέτες ή τα κλειδιά.

Η χρήση της κρυφής μνήμης μπορεί επίσης να εξαρτάται από τη διεύθυνση if – το περιεχόμενο θα αποθηκευτεί στην κρυφή μνήμη μόνο εάν πληρούται η συνθήκη:

{cache $id, if: !$form->isSubmitted()}
	{$form}
{/cache}

Αποθήκες

Ένας αποθηκευτικός χώρος είναι ένα αντικείμενο που αντιπροσωπεύει τον τόπο όπου αποθηκεύονται φυσικά τα δεδομένα. Μπορούμε να χρησιμοποιήσουμε μια βάση δεδομένων, έναν διακομιστή Memcached ή τον πιο διαθέσιμο αποθηκευτικό χώρο, που είναι τα αρχεία στο δίσκο.

Αποθήκευση Περιγραφή
FileStorage προεπιλεγμένη αποθήκευση με αποθήκευση σε αρχεία στο δίσκο
MemcachedStorage χρησιμοποιεί τον διακομιστή Memcached
MemoryStorage τα δεδομένα βρίσκονται προσωρινά στη μνήμη
SQLiteStorage τα δεδομένα αποθηκεύονται σε βάση δεδομένων SQLite
DevNullStorage τα δεδομένα δεν αποθηκεύονται – για δοκιμαστικούς σκοπούς

Λαμβάνετε το αντικείμενο αποθήκευσης περνώντας το χρησιμοποιώντας dependency injection με τον τύπο Nette\Caching\Storage. Από προεπιλογή, η Nette παρέχει ένα αντικείμενο FileStorage που αποθηκεύει δεδομένα σε έναν υποφάκελο cache στον κατάλογο για προσωρινά αρχεία.

Μπορείτε να αλλάξετε την αποθήκευση στη διαμόρφωση:

services:
	cache.storage: Nette\Caching\Storages\DevNullStorage

FileStorage

Γράφει την κρυφή μνήμη σε αρχεία στο δίσκο. Η αποθήκευση Nette\Caching\Storages\FileStorage είναι πολύ καλά βελτιστοποιημένη για την απόδοση και πάνω απ' όλα εξασφαλίζει πλήρη ατομικότητα των λειτουργιών. Τι σημαίνει αυτό; Ότι κατά τη χρήση της κρυφής μνήμης δεν μπορεί να συμβεί να διαβάσουμε ένα αρχείο που δεν έχει ακόμα γραφτεί πλήρως από κάποιο άλλο νήμα ή να το διαγράψει κάποιος „κάτω από τα χέρια σας“. Η χρήση της κρυφής μνήμης είναι επομένως απολύτως ασφαλής.

Αυτή η αποθήκευση έχει επίσης ένα σημαντικό ενσωματωμένο χαρακτηριστικό που αποτρέπει την ακραία αύξηση της χρήσης της CPU όταν η κρυφή μνήμη διαγράφεται ή ψύχεται (δηλαδή δεν δημιουργείται). Αυτή είναι η πρόληψη stampede cache. Συμβαίνει ότι σε μια στιγμή υπάρχουν πολλές ταυτόχρονες αιτήσεις που θέλουν το ίδιο πράγμα από την κρυφή μνήμη (π.χ. το αποτέλεσμα ενός ακριβού ερωτήματος SQL) και επειδή αυτό δεν έχει αποθηκευτεί στην κρυφή μνήμη, όλες οι διεργασίες αρχίζουν να εκτελούν το ίδιο ερώτημα SQL. Το φορτίο του επεξεργαστή πολλαπλασιάζεται και μπορεί να συμβεί ακόμη και να μην μπορεί κανένα νήμα να ανταποκριθεί εντός του χρονικού ορίου, να μη δημιουργηθεί η κρυφή μνήμη και να καταρρεύσει η εφαρμογή. Ευτυχώς, η κρυφή μνήμη στο Nette λειτουργεί με τέτοιο τρόπο ώστε όταν υπάρχουν πολλαπλές ταυτόχρονες αιτήσεις για ένα στοιχείο, αυτό δημιουργείται μόνο από το πρώτο νήμα, τα υπόλοιπα περιμένουν και στη συνέχεια χρησιμοποιούν το παραγόμενο αποτέλεσμα.

Παράδειγμα δημιουργίας ενός FileStorage:

// η αποθήκευση θα είναι ο κατάλογος '/path/to/temp' στο δίσκο
$storage = new Nette\Caching\Storages\FileStorage('/path/to/temp');

MemcachedStorage

Ο διακομιστής Memcached είναι ένα κατανεμημένο σύστημα αποθήκευσης υψηλής απόδοσης, του οποίου ο προσαρμογέας είναι Nette\Caching\Storages\MemcachedStorage. Στη διαμόρφωση, καθορίστε τη διεύθυνση IP και τη θύρα, εάν διαφέρουν από το πρότυπο 11211.

Απαιτεί την επέκταση PHP memcached.

services:
	cache.storage: Nette\Caching\Storages\MemcachedStorage('10.0.0.5')

MemoryStorage

Nette\Caching\Storages\MemoryStorage είναι ένας αποθηκευτικός χώρος που αποθηκεύει δεδομένα σε έναν πίνακα PHP και έτσι χάνονται όταν τερματιστεί η αίτηση.

SQLiteStorage

Η βάση δεδομένων SQLite και ο προσαρμογέας Nette\Caching\Storages\SQLiteStorage προσφέρουν έναν τρόπο προσωρινής αποθήκευσης σε ένα μόνο αρχείο στο δίσκο. Η ρύθμιση παραμέτρων θα καθορίσει τη διαδρομή προς αυτό το αρχείο.

Απαιτεί τις επεκτάσεις PHP pdo και pdo_sqlite.

services:
	cache.storage: Nette\Caching\Storages\SQLiteStorage('%tempDir%/cache.db')

DevNullStorage

Μια ειδική υλοποίηση της αποθήκευσης είναι η Nette\Caching\Storages\DevNullStorage, η οποία στην πραγματικότητα δεν αποθηκεύει καθόλου δεδομένα. Επομένως, είναι κατάλληλη για δοκιμές αν θέλουμε να εξαλείψουμε την επίδραση της κρυφής μνήμης.

Χρήση της κρυφής μνήμης στον κώδικα

Όταν χρησιμοποιείτε προσωρινή αποθήκευση στον κώδικα, έχετε δύο τρόπους για να το κάνετε. Ο πρώτος είναι ότι παίρνετε το αντικείμενο αποθήκευσης περνώντας το με τη χρήση dependency injection και στη συνέχεια δημιουργείτε ένα αντικείμενο Cache:

use Nette;

class ClassOne
{
	private Nette\Caching\Cache $cache;

	public function __construct(Nette\Caching\Storage $storage)
	{
		$this->cache = new Nette\Caching\Cache($storage, 'my-namespace');
	}
}

Ο δεύτερος τρόπος είναι ότι παίρνετε το αντικείμενο αποθήκευσης Cache:

class ClassTwo
{
	public function __construct(
		private Nette\Caching\Cache $cache,
	) {
	}
}

Το αντικείμενο Cache δημιουργείται στη συνέχεια απευθείας στη διαμόρφωση ως εξής:

services:
	- ClassTwo( Nette\Caching\Cache(namespace: 'my-namespace') )

Περιοδικό

Η Nette αποθηκεύει ετικέτες και προτεραιότητες σε ένα λεγόμενο ημερολόγιο. Από προεπιλογή, χρησιμοποιείται το SQLite και το αρχείο journal.s3db γι' αυτό, ενώ απαιτούνται οι επεκτάσεις **PHP pdo και pdo_sqlite. **

Μπορείτε να αλλάξετε το ημερολόγιο στη διαμόρφωση:

services:
	cache.journal: MyJournal

Υπηρεσίες DI

Αυτές οι υπηρεσίες προστίθενται στο δοχείο DI:

Όνομα Τύπος Περιγραφή
cache.journal Nette\Caching\Storages\Journal journal
cache.storage Nette\Caching\Storage repository

Απενεργοποίηση της κρυφής μνήμης

Ένας από τους τρόπους για να απενεργοποιήσετε την προσωρινή αποθήκευση στην εφαρμογή είναι να ορίσετε τον αποθηκευτικό χώρο σε DevNullStorage:

services:
	cache.storage: Nette\Caching\Storages\DevNullStorage

Αυτή η ρύθμιση δεν επηρεάζει την προσωρινή αποθήκευση των προτύπων στο Latte ή στο DI container, καθώς αυτές οι βιβλιοθήκες δεν χρησιμοποιούν τις υπηρεσίες της nette/caching και διαχειρίζονται την προσωρινή τους μνήμη ανεξάρτητα. Επιπλέον, η κρυφή μνήμη τους δεν χρειάζεται να απ ενεργοποιηθεί στη λειτουργία ανάπτυξης.