[REVIEW] PSR-16 Simple Cache

1,067 views
Skip to first unread message

Jordi Boggiano

unread,
Nov 16, 2016, 9:22:20 AM11/16/16
to php...@googlegroups.com
Heya,

We believe PSR-16, Simple Cache, is now ready for final review. As
coordinator, I hereby open the mandatory review period prior to a formal
acceptance vote; voting will begin no earlier than December 1st, 2016.

Here are links to the most current version and its meta document:

https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md

https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md


The package containing the interfaces is there:

https://github.com/php-fig/simplecache


The latest important changes to the interfaces can be found at:

https://github.com/php-fig/simplecache/releases/tag/0.2.0


And FWIW, Scrapbook already provides a PSR-16 implementation in its
upcoming release:
https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php


Thanks for your time reviewing!

Cheers

--
Jordi Boggiano
@seldaek - http://seld.be

Alexander Makarov

unread,
Nov 16, 2016, 10:40:31 AM11/16/16
to PHP Framework Interoperability Group
Looks excellent.

Andrew Carter

unread,
Nov 16, 2016, 11:03:07 AM11/16/16
to PHP Framework Interoperability Group
Good work.

One thing that always bothered me from a user perspective was not being able to put an item in the cache that doesn't expire (different from a default expiration time). Having to create times really far in advance is messy, and you never know if you're going to run into 2038 bugs etc. It's also quite common to have an entry that you don't want to expire, because you'll invalidate it yourself or wait for the cache to drop it when it's full.

For me, saying that a NULL ttl means some default value somewhere is a waste of a feature. If I wanted a default value, my code can (and should) explicitly take care of that. I think documenting NULL to mean "This item doesn't expire. If the cache driver doesn't not support items that do not expire, the ttl will be set to the maximum possible."

Cheers,

Andrew

Andrew Carter

unread,
Nov 16, 2016, 11:08:39 AM11/16/16
to PHP Framework Interoperability Group
Sorry for the double post, what's the reasoning behind returning a boolean if the set() operation fails? I'd naturally expect that to be an exception (it's not the same as a cache miss, there must have been some error).


On Wednesday, November 16, 2016 at 2:22:20 PM UTC, Jordi Boggiano wrote:

Jordi Boggiano

unread,
Nov 16, 2016, 11:15:21 AM11/16/16
to php...@googlegroups.com
This was carried over from PSR-6 tbh, and my understanding is that "an
Implementing Library MAY use a configured default duration" means you
can very well treat null as "do not expire ever".

If you read the symfony cache docs for example [1], it shows that by
default they treat it that way, and I'd expect others do that too but I
havent' researched in depth.

As such I am ok leaving it as is because the common-sense
implementations will do it right, and it doesn't warrant breaking away
from PSR-6 IMO.

Cheers

[1]
https://symfony.com/doc/current/components/cache/cache_items.html#cache-item-expiration

On 16/11/2016 17:03, Andrew Carter wrote:
> Good work.
>
> One thing that always bothered me from a user perspective was not being
> able to put an item in the cache that doesn't expire (different from a
> default expiration time). Having to create times really far in advance
> is messy, and you never know if you're going to run into 2038 bugs etc.
> It's also quite common to have an entry that you don't want to expire,
> because you'll invalidate it yourself or wait for the cache to drop it
> when it's full.
>
> For me, saying that a NULL ttl means some default value somewhere is a
> waste of a feature. If I wanted a default value, my code can (and
> should) explicitly take care of that. I think documenting NULL to mean
> "This item doesn't expire. If the cache driver doesn't not support items
> that do not expire, the ttl will be set to the maximum possible."
>
> Cheers,
>
> Andrew
>
> On Wednesday, November 16, 2016 at 2:22:20 PM UTC, Jordi Boggiano wrote:
>
> Heya,
>
> We believe PSR-16, Simple Cache, is now ready for final review. As
> coordinator, I hereby open the mandatory review period prior to a
> formal
> acceptance vote; voting will begin no earlier than December 1st, 2016.
>
> Here are links to the most current version and its meta document:
>
> https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md
> <https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md>
>
>
> https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md
> <https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md>
>
>
>
> The package containing the interfaces is there:
>
> https://github.com/php-fig/simplecache
> <https://github.com/php-fig/simplecache>
>
>
> The latest important changes to the interfaces can be found at:
>
> https://github.com/php-fig/simplecache/releases/tag/0.2.0
> <https://github.com/php-fig/simplecache/releases/tag/0.2.0>
>
>
> And FWIW, Scrapbook already provides a PSR-16 implementation in its
> upcoming release:
> https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php
> <https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php>
>
>
>
> Thanks for your time reviewing!
>
> Cheers
>
> --
> Jordi Boggiano
> @seldaek - http://seld.be
>
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/2dadde75-0559-4a64-a77d-e13bbe1e5690%40googlegroups.com
> <https://groups.google.com/d/msgid/php-fig/2dadde75-0559-4a64-a77d-e13bbe1e5690%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.

Jordi Boggiano

unread,
Nov 16, 2016, 11:19:20 AM11/16/16
to php...@googlegroups.com
This was also carried over from PSR-6 where Pool::save() returns bool.

I am not really sure what's best here, I expect most implementation will
throw anyway if they can't connect to the cache, and in other instances
there is no reason a write should fail AFAIK.

Any other opinions on this?

On 16/11/2016 17:08, Andrew Carter wrote:
> Sorry for the double post, what's the reasoning behind returning a
> boolean if the set() operation fails? I'd naturally expect that to be an
> exception (it's not the same as a cache miss, there must have been some
> error).
>
> On Wednesday, November 16, 2016 at 2:22:20 PM UTC, Jordi Boggiano wrote:
>
> Heya,
>
> We believe PSR-16, Simple Cache, is now ready for final review. As
> coordinator, I hereby open the mandatory review period prior to a
> formal
> acceptance vote; voting will begin no earlier than December 1st, 2016.
>
> Here are links to the most current version and its meta document:
>
> https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md
> <https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md>
>
>
> https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md
> <https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md>
>
>
>
> The package containing the interfaces is there:
>
> https://github.com/php-fig/simplecache
> <https://github.com/php-fig/simplecache>
>
>
> The latest important changes to the interfaces can be found at:
>
> https://github.com/php-fig/simplecache/releases/tag/0.2.0
> <https://github.com/php-fig/simplecache/releases/tag/0.2.0>
>
>
> And FWIW, Scrapbook already provides a PSR-16 implementation in its
> upcoming release:
> https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php
> <https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php>
>
>
>
> Thanks for your time reviewing!
>
> Cheers
>
> --
> Jordi Boggiano
> @seldaek - http://seld.be
>
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/8fb9871d-2e1b-4922-bfc7-b123bec6528f%40googlegroups.com
> <https://groups.google.com/d/msgid/php-fig/8fb9871d-2e1b-4922-bfc7-b123bec6528f%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.


Jeroen De Dauw

unread,
Nov 16, 2016, 11:25:19 AM11/16/16
to php...@googlegroups.com
Hey,

How does this CounterInterface fit into the PSR? It seems a lot more specific than the cache interface itself. I know a lot of places where I'd have use for the later but not for the former.

Cheers
Software craftsmanship advocate | Developer at Wikimedia Germany
~=[,,_,,]:3

Jordi Boggiano

unread,
Nov 16, 2016, 11:36:46 AM11/16/16
to php...@googlegroups.com
That's why it's now in a separate interface, see the meta document and
specifically #4 paragraph 2.

I realize this is not useful for everybody, but it has a low cost of
implementation for cache implementations where backends support it, so
IMO it's worth having.

Cheers
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/CAMhmagDiF1LYNbRYdkVQA9WmH3AUYE5TArJhhmVpEyU8oNcx9Q%40mail.gmail.com
> <https://groups.google.com/d/msgid/php-fig/CAMhmagDiF1LYNbRYdkVQA9WmH3AUYE5TArJhhmVpEyU8oNcx9Q%40mail.gmail.com?utm_medium=email&utm_source=footer>.

Stefano Torresi

unread,
Nov 16, 2016, 2:04:27 PM11/16/16
to php...@googlegroups.com
Il giorno mer 16 nov 2016 alle ore 17:19 Jordi Boggiano <j.bog...@seld.be> ha scritto:
This was also carried over from PSR-6 where Pool::save() returns bool.

I am not really sure what's best here, I expect most implementation will
throw anyway if they can't connect to the cache, and in other instances
there is no reason a write should fail AFAIK.

Any other opinions on this?

I don't see any compelling advantage in the boolean return value and I'd prefer leaving it out, but there were a few people who argued in favor of it during PSR-6 review.

As a side note, out of the most downloaded non-PSR-6 libraries listed in the first pages of Packagist, Zend\Cache and Doctrine\Cache do follow this convention, while almost every other don't.

Cees-Jan Kiewiet

unread,
Nov 16, 2016, 4:59:54 PM11/16/16
to php...@googlegroups.com
This PSR looks splendid, well done. There are how ever a few concerns with regards to async PHP. I'm aware there isn't a Promise PSR yet but is it acceptable within this spec to return a promise instead of the actual value on a get? Or to resolve or reject a promise on set instead of returning true/false directly.

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/CAFojS1sV1YTy5A-rjqq5syGPMbVAcBn1WA-D62BDsgV0yVp3wg%40mail.gmail.com.

Larry Garfield

unread,
Nov 16, 2016, 5:13:40 PM11/16/16
to php...@googlegroups.com
The reasoning here for PSR-6 was that a broken cache should not result
in a broken program. If your cache is b0rked, then everything becomes a
cache miss but the app continues to run, just slowly. (Maybe unbearably
slowly, but technically still runs.) If a failed set threw an exception
then your cache server hiccuping would crash your whole application,
which is doubleplusungood.

I believe the same logic applies equally well to PSR-16.

--Larry Garfield

Jordi Boggiano

unread,
Nov 17, 2016, 3:05:47 AM11/17/16
to php...@googlegroups.com
Thanks for the clarifications Larry.

Jordi Boggiano

unread,
Nov 17, 2016, 3:44:49 AM11/17/16
to php...@googlegroups.com
We had a quick chat off list and I believe Cees-Jan agrees with me that
this is not really feasible as is.

Having promise responses without a promise spec is not doable, and
having optional promise responses means the interface can not be relied
upon at all in libraries as it may return values or may return promises
depending on which PSR-16 implementation you'd use.

One can still use a promise-based cache library in their app of course,
but they'd have to use a PSR-6 or PSR-16 one to pass into libraries that
require a cache.

Cheers

On 16/11/2016 22:59, Cees-Jan Kiewiet wrote:
> This PSR looks splendid, well done. There are how ever a few concerns
> with regards to async PHP. I'm aware there isn't a Promise PSR yet but
> is it acceptable within this spec to return a promise instead of the
> actual value on a get? Or to resolve or reject a promise on set instead
> of returning true/false directly.
>
> On Wed, Nov 16, 2016 at 8:04 PM, Stefano Torresi <ste...@torresi.io
> <mailto:ste...@torresi.io>> wrote:
>
>
> Il giorno mer 16 nov 2016 alle ore 17:19 Jordi Boggiano
> <j.bog...@seld.be <mailto:j.bog...@seld.be>> ha scritto:
>
> This was also carried over from PSR-6 where Pool::save() returns
> bool.
>
> I am not really sure what's best here, I expect most
> implementation will
> throw anyway if they can't connect to the cache, and in other
> instances
> there is no reason a write should fail AFAIK.
>
> Any other opinions on this?
>
>
> I don't see any compelling advantage in the boolean return value and
> I'd prefer leaving it out, but there were a few people who argued in
> favor of it during PSR-6 review.
>
> As a side note, out of the most downloaded non-PSR-6 libraries
> listed in the first pages of Packagist, Zend\Cache and
> Doctrine\Cache do follow this convention, while almost every other
> don't.
>
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> <https://groups.google.com/d/msgid/php-fig/CAFojS1sV1YTy5A-rjqq5syGPMbVAcBn1WA-D62BDsgV0yVp3wg%40mail.gmail.com?utm_medium=email&utm_source=footer>.
>
> For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/CAPY1sU8tU7VrWvuSMjxMwd5qMvDfQbgmc0E_P2dowJMoHt%3D%2BDQ%40mail.gmail.com
> <https://groups.google.com/d/msgid/php-fig/CAPY1sU8tU7VrWvuSMjxMwd5qMvDfQbgmc0E_P2dowJMoHt%3D%2BDQ%40mail.gmail.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.


Andrew Carter

unread,
Nov 17, 2016, 12:43:35 PM11/17/16
to PHP Framework Interoperability Group
Not sure I fully understand that - as a user I can't rely on common sense implementations doing it right. If it's not part of the standard, I can't guarantee it as a feature and I can't use it.

My only course of action for using that feature would be tightly coupling to a cache library that did support items which don't expire, and losing interoperability (as I have done in the past).

Jordi Boggiano

unread,
Nov 17, 2016, 2:09:15 PM11/17/16
to php...@googlegroups.com
I see what you mean, but down the line it doesn't actually matter as it
is merely a cache.

You can never rely on anything you store in there being there when you
want to read it again, no matter what expiration you set. The backend
might be full and wiping stuff early, etc. All you can do is *request*
that something be stored for a given amount of time.

Given that fact I think that the null as it is now is kinda ok, it lets
an application developer if they so wish configure their lib to make all
cache entries expire after X hours by default, or they can say no
actually keep everything forever unless otherwise specified, or if you
have specific needs as a library author you can give specific expiration
times. It adds a tiny bit of control for the app developer, and doesn't
really remove anything from lib developers as they can anyway not rely
on any guarantee from the cache.

Does this make sense to you?

Cheers,
Jordi
> > an email to php-fig+u...@googlegroups.com <javascript:>
> > <mailto:php-fig+u...@googlegroups.com <javascript:>>.
> > To post to this group, send email to php...@googlegroups.com
> <javascript:>
> > <mailto:php...@googlegroups.com <javascript:>>.
> <https://groups.google.com/d/msgid/php-fig/2dadde75-0559-4a64-a77d-e13bbe1e5690%40googlegroups.com?utm_medium=email&utm_source=footer
> <https://groups.google.com/d/optout>.
>
>
> --
> Jordi Boggiano
> @seldaek - http://seld.be
>
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/21e8071e-c6a6-484d-9a70-56413b336a0a%40googlegroups.com
> <https://groups.google.com/d/msgid/php-fig/21e8071e-c6a6-484d-9a70-56413b336a0a%40googlegroups.com?utm_medium=email&utm_source=footer>.

Andrew Carter

unread,
Nov 17, 2016, 3:21:37 PM11/17/16
to PHP Framework Interoperability Group
I don't agree with the decision, but I understand the trade off.

What we're trading is the ability to set a default value in the cache configuration at the cost of not having an interoperable way for developers to create items which don't expire.

From what I can tell, the PSR-6 API that we are both replacing and trying to maintain compatibility with (?) is the only cache that operates in this manner. Most other caches operate with a NULL or 0 TTL corresponding to an entry that doesn't have a natural expiry time: apc, memcache, redis, xcache, doctrine, the symfony one you mentioned, etc..

This is my last post on the subject, but I'd like whoever calls the vote to make sure that this decision and the existence of our discussion has been made clear to the voting members. I'm not sure if there's any requirement for the voting threads to draw attention to this - but I think that would be a good precedent to set if not.

My last post on the subject as I think we understand each other, just disagree on the outcome.

Cheers,

Andrew

Jordi Boggiano

unread,
Nov 18, 2016, 4:54:45 AM11/18/16
to php...@googlegroups.com
I will try to add it to the meta document or maybe add more text to the
spec regarding this default expiration. I think that's the best way to
make people aware of it.

That said, the symfony cache I mentioned for example, is a PSR-6
implementation, and will most likely implement PSR-16, while letting you
have items that don't expire if you use NULL. You just don't get that
guarantee at the spec level, I see that.

Cheers

On 17/11/2016 21:21, Andrew Carter wrote:
> I don't agree with the decision, but I understand the trade off.
>
> What we're trading is the ability to set a default value in the cache
> configuration at the cost of not having an interoperable way for
> developers to create items which don't expire.
>
> From what I can tell, the PSR-6 API that we are both replacing and
> trying to maintain compatibility with (?) is the only cache that
> operates in this manner. Most other caches operate with a NULL or 0 TTL
> corresponding to an entry that doesn't have a natural expiry time: apc
> <http://php.net/manual/en/function.apc-store.php>, memcache
> <http://php.net/manual/en/memcached.expiration.php>, redis
> <http://redis.io/commands/persist>, xcache
> <https://xcache.lighttpd.net/wiki/XcacheIni>, doctrine
> <http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/caching.html#saving>,
> https://groups.google.com/d/msgid/php-fig/21e8071e-c6a6-484d-9a70-56413b336a0a%40googlegroups.com
> <https://groups.google.com/d/msgid/php-fig/21e8071e-c6a6-484d-9a70-56413b336a0a%40googlegroups.com>
>
> >
> <https://groups.google.com/d/msgid/php-fig/21e8071e-c6a6-484d-9a70-56413b336a0a%40googlegroups.com?utm_medium=email&utm_source=footer
> <https://groups.google.com/d/msgid/php-fig/21e8071e-c6a6-484d-9a70-56413b336a0a%40googlegroups.com?utm_medium=email&utm_source=footer>>.
>
> > For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
>
> --
> Jordi Boggiano
> @seldaek - http://seld.be
>
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/0c6b40bb-ae5a-4bd3-83f0-f617c8d0d4aa%40googlegroups.com
> <https://groups.google.com/d/msgid/php-fig/0c6b40bb-ae5a-4bd3-83f0-f617c8d0d4aa%40googlegroups.com?utm_medium=email&utm_source=footer>.

Nicolas Grekas

unread,
Nov 18, 2016, 11:22:24 AM11/18/16
to php...@googlegroups.com
Hi,

PSR-6 makes it very clear that the expiration date/interval is really a maximum and that implementations are free to make the actual item removal happen anytime before.
Actually, memcached kind of proved that *for the cache use case*, it can be verify effective to let the backend clean items use LRU or similar.
If PSR-6, or 16 now, would have added a requirement for storages to be able to store items that never expires, that would have immediately disqualified these strategies and related backends.

Which means to me eveything is already fine for the cache use case.

But this also means that PSR-6/16 are NOT fine for non-cache related use cases (e.g. session storage on PSR-6 is a BAD idea exactly because of this).

Regards,
Nicolas



To post to this group, send email to php...@googlegroups.com


--
Jordi Boggiano
@seldaek - http://seld.be

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/e7ad073d-7335-07db-3b79-9a5e4b566523%40seld.be.

Paul Dragoonis

unread,
Nov 18, 2016, 6:02:01 PM11/18/16
to php...@googlegroups.com
Hey,

Just wanted to say thanks everyone for the compliments and for the constructive feedback.

If there's any more clarifications in the spec that you feel are *not* tight enough please continue to raise here or make a PR so we can review it.

Many thanks,
Paul

Matteo Beccati

unread,
Nov 23, 2016, 11:08:14 AM11/23/16
to php...@googlegroups.com
Hi Jordi (et al.),

nice job!

Tbh I was a bit surprised as I haven't seen any discussion about it at
all after the entrance vote and I wasn't aware of it being worked on
anywhere outside this ML. My fault, as I've probably missed that
communication and didn't check or ask around.

That said, below are my major gripes with it, inherited from PSR-6.

I understand where "MUST treat an item as expired once its Expiration
Time is reached" comes from, and I would agree, but for a cache it makes
little sense to be so strict and adamant about it. An entry that has a
TTL of 30 seconds is probably going to be fine at 31s too, especially if
expiration can't be expressed as a point in time.

Relaxing that would allow implementations to conform to the PSR-6
interface and adding stampede protection the same way apc(u) / squid do,
i.e. returning a slightly stale item while a single process is updating
the cache.

Not a deal-breaker, but "SHOULD treat an item as expired" can be
implemented as "always treat..." if anyone so desires, whereas the
opposite is not possible.

Other than that, I also am not very fond of null meaning either never or
some unspecified default value. A library would be forced to pick one as
there's no way to set an item to never expire if a default is available.
I personally like being able to specify a default TTL, but I would trade
that in exchange for something cleaner and clearer.

Alternatively, I'd suggest adding something like
CacheInterface::setDefaultTTL() and CacheInterface::TTL_NEVER = -1, with
support for the latter being subject to the actual storage capabilities.


Cheers
Matteo Beccati

Development & Consulting - http://www.beccati.com/

Jordi Boggiano

unread,
Nov 23, 2016, 4:57:16 PM11/23/16
to php...@googlegroups.com
On 23/11/2016 17:08, Matteo Beccati wrote:
> Tbh I was a bit surprised as I haven't seen any discussion about it at
> all after the entrance vote and I wasn't aware of it being worked on
> anywhere outside this ML. My fault, as I've probably missed that
> communication and didn't check or ask around.

A few people have came forward with feedback here and there and we took
it where we could, but overall as this thread shows people only have
nitpicky gripes (no offense meant to anyone, details matter) and are
otherwise ok with the spec I think.

> I understand where "MUST treat an item as expired once its Expiration
> Time is reached" comes from, and I would agree, but for a cache it makes
> little sense to be so strict and adamant about it. An entry that has a
> TTL of 30 seconds is probably going to be fine at 31s too, especially if
> expiration can't be expressed as a point in time.
>
> Relaxing that would allow implementations to conform to the PSR-6
> interface and adding stampede protection the same way apc(u) / squid do,
> i.e. returning a slightly stale item while a single process is updating
> the cache.
>
> Not a deal-breaker, but "SHOULD treat an item as expired" can be
> implemented as "always treat..." if anyone so desires, whereas the
> opposite is not possible.

I am a believer in pragmatism and given that I'd say an implementation
that does this even if it violates the spec is totally fine as long as
the user chooses it willingly and they know what it means then whatever.
I don't think SHOULD or MUST will change a whole lot in practice there,
but I also don't really have anything against changing it.. Anyone else
got something to add?

> Alternatively, I'd suggest adding something like
> CacheInterface::setDefaultTTL() and CacheInterface::TTL_NEVER = -1, with
> support for the latter being subject to the actual storage capabilities.

I am rather against setDefaultTTL because that'd mean every lib and user
has to constantly reset the default TTL to make sure they have the right
one set, so you might as well just set the TTL you want.

TTL_NEVER however sounds like a good addition, I'd be curious to hear
other people on this.

Larry Garfield

unread,
Nov 24, 2016, 4:27:31 PM11/24/16
to php...@googlegroups.com
On 11/23/2016 10:57 PM, Jordi Boggiano wrote:
>
>> I understand where "MUST treat an item as expired once its Expiration
>> Time is reached" comes from, and I would agree, but for a cache it makes
>> little sense to be so strict and adamant about it. An entry that has a
>> TTL of 30 seconds is probably going to be fine at 31s too, especially if
>> expiration can't be expressed as a point in time.
>>
>> Relaxing that would allow implementations to conform to the PSR-6
>> interface and adding stampede protection the same way apc(u) / squid do,
>> i.e. returning a slightly stale item while a single process is updating
>> the cache.
> >
> > Not a deal-breaker, but "SHOULD treat an item as expired" can be
> > implemented as "always treat..." if anyone so desires, whereas the
> > opposite is not possible.
>
> I am a believer in pragmatism and given that I'd say an implementation
> that does this even if it violates the spec is totally fine as long as
> the user chooses it willingly and they know what it means then
> whatever. I don't think SHOULD or MUST will change a whole lot in
> practice there, but I also don't really have anything against changing
> it.. Anyone else got something to add?

We discussed the "grace period/stampede problem" at length for PSR-6.
The end conclusion was that an implementation that wants to and is able
to can make a grace period before expiration rather than after; viz,
auto-regenerate a value the first time it's requested in the 5 min
before it's expiration time rather than the 5 min after it's expiration
time. The net effect is the same. The expiration time is a hard limit,
by design. "After this timestamp, DO NOT WANT!"

I believe PSR-6 should mimic that behavior for compatibility purposes,
so would be against changing the MUST to SHOULD.

>
>> Alternatively, I'd suggest adding something like
>> CacheInterface::setDefaultTTL() and CacheInterface::TTL_NEVER = -1, with
>> support for the latter being subject to the actual storage capabilities.
>
> I am rather against setDefaultTTL because that'd mean every lib and
> user has to constantly reset the default TTL to make sure they have
> the right one set, so you might as well just set the TTL you want.

Agreed. Setting the configuration on a cache pool (which PSR-16 is as
well, effectively) is out of scope for the spec.

> TTL_NEVER however sounds like a good addition, I'd be curious to hear
> other people on this.
>
> Cheers


We discussed this at phpworld. Michael, do you have the notes of that
conversation and what the outcome was? My general recollection was a
consensus around "be consistent with PSR-6 to avoid ugly and confusing
bugs", but I don't recall the exact conclusion on TTL-never.


--Larry Garfield

Rasmus Schultz

unread,
Nov 25, 2016, 5:21:24 AM11/25/16
to PHP Framework Interoperability Group
Hey Jordi,

This is pretty exciting - and we're already using PSR-16, so it's good to see this nearing completion :-)

I have a question about the design, however - to which I did not find an answer in the doc or meta-doc.

PSR-16 does not support the concept of multiple cache collections.

First, let me say that I think this is the right decision - supporting multiple connections with a single cache service seems to imply that a single cache service can serve all caching purposes, for all consumers, centrally, in your project, which, I believe, is false; it implies that there's a single "right" cache for all consumers, which isn't true.

For example, a cache for a few thousand small user-records might require a very different type of cache from one that caches millions of rendered articles - so I don't actually want the convenience of a global cache, I want to be forced to make decisions about caching for each consumer based on what's relevant to each of them.

However, I also don't want to set up a new cache server for every consumer. I likely do have several consumers that need to store cache-data in a shared Memcache server.

I also don't want each consumer to have to worry about prefixing key or something - which, even if every consumer took care to prefix keys, a single PSR-16 cache instance still can't serve multiple consumers, because I'd be unable to, say, clear the small collection of cached user-data without also clearing the enormous multi-million cache of rendered articles.

So the concept of multiple collections ("pools" in PSR-16) is necessary.

Since there is no collection-concept in PSR-16, I have to assume that the intent is for each cache-instance to host a single collection of cache-entries? (and for the reasons describe above, I think that's the right approach, and it matches the reality of making caching-decisions much better than PSR-6.)

Assuming I understand this correctly, I think it's really important to describe that concept in the document, or at least in the meta.

Assuming the idea is to have multiple cache-instances, that of course doesn't prevent you from backing them all with a single Memcached server - it's just a matter of having the right constructor signature, e.g. one that includes a collection prefix, so that multiple PSR-16 cache-instances can host collections on the same physical Memcached server, without, for example, key collisions, and without calls to clear() on one instance affecting the other.

For something like a flat file-cache, this is extremely easy to follow and implement - it's probably harder for something like Memcached

I guess I'm looking for a clear definition of what the PSR-16 cache-abstraction represents: a cache *server* or a cache *collection*?

The distinction is *extremely* important for the definition, implementation and understanding of, for example, flush() - compared with Doctrine cache, am I flushing the contents of the entire server, as in Doctrine's flush(), or am I flushing the contents of a collection of cache-entries on the server, as per Doctrine's deleteAll()?

Assuming I understand the concept correctly, I would *not* expect a cache-instance to flush the entire server, but rather to flush only the collection represented by the cache-instance.

Doctrine's cache-abstraction includes the concept of "namespaces", which equate to collection IDs - but here the distinction is clear, since it includes two distinct methods for clearing a collection with deleteAll() vs clearing the entire server with flush().

With PSR-16, there is only method, flush(), so it's extremely important we understand what precisely the scope of a cache-instance is: a entire server, or a collection on a server?

- Rasmus

Rasmus Schultz

unread,
Nov 25, 2016, 7:46:23 AM11/25/16
to PHP Framework Interoperability Group
Oh, also - a minor question about the decrement() method. Does it go into negative when you hit zero, or does it return false, or what?


On Wednesday, November 16, 2016 at 3:22:20 PM UTC+1, Jordi Boggiano wrote:

Rasmus Schultz

unread,
Nov 25, 2016, 8:01:09 AM11/25/16
to PHP Framework Interoperability Group
One, and one last minor thing... regarding the DateInterval overload for $ttl in set() ... well ... why?

Everyone is going to have to write ugly code to convert these into seconds.

Ironically, the answer is first thing that auto-completes on google as soon as you type in "dateinterval", but.... copy/pasting this garbage everywhere, well, why?

Being able to specify the TTL as DateInterval is just a clumsy, round-about way to pass an integer argument, is it not?


$seconds = ($delta->s)
         + ($delta->i * 60)
         + ($delta->h * 60 * 60)
         + ($delta->d * 60 * 60 * 24)
         + ($delta->m * 60 * 60 * 24 * 30)
         + ($delta->y * 60 * 60 * 24 * 365);

Matteo Beccati

unread,
Nov 25, 2016, 8:04:02 AM11/25/16
to php...@googlegroups.com
Hi Rasmus,

I agree DateInterval is overkill. Unless you need to be precise when
passing the DST boundaries or month lengths. But then again, to me
that's not really how a cache is supposed to be used.


Cheers

On 25/11/2016 14:01, Rasmus Schultz wrote:
> One, and one last minor thing... regarding the DateInterval overload for
> $ttl in set() ... well ... why?
>
> Everyone is going to have to write ugly code to convert these into seconds.
>
> Ironically, the answer is first thing that auto-completes on google as
> soon as you type in "dateinterval", but.... copy/pasting this garbage
> everywhere, well, why?
>
> Being able to specify the TTL as DateInterval is just a clumsy,
> round-about way to pass an integer argument, is it not?
>
>
> |$seconds = ($delta->s)+($delta->i *60)+($delta->h *60*60)+($delta->d
> *60*60*24)+($delta->m *60*60*24*30)+($delta->y *60*60*24*365);|
>
>
>
> On Friday, November 25, 2016 at 1:46:23 PM UTC+1, Rasmus Schultz wrote:
>
> Oh, also - a minor question about the decrement() method. Does it go
> into negative when you hit zero, or does it return false, or what?
>
> On Wednesday, November 16, 2016 at 3:22:20 PM UTC+1, Jordi Boggiano
> wrote:
>
> Heya,
>
> We believe PSR-16, Simple Cache, is now ready for final review. As
> coordinator, I hereby open the mandatory review period prior to
> a formal
> acceptance vote; voting will begin no earlier than December 1st,
> 2016.
>
> Here are links to the most current version and its meta document:
>
> https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md
> <https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md>
>
>
> https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md
> <https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md>
>
>
>
> The package containing the interfaces is there:
>
> https://github.com/php-fig/simplecache
> <https://github.com/php-fig/simplecache>
>
>
> The latest important changes to the interfaces can be found at:
>
> https://github.com/php-fig/simplecache/releases/tag/0.2.0
> <https://github.com/php-fig/simplecache/releases/tag/0.2.0>
>
>
> And FWIW, Scrapbook already provides a PSR-16 implementation in its
> upcoming release:
> https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php
> <https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php>
>
>
>
> Thanks for your time reviewing!
>
> Cheers
>
> --
> Jordi Boggiano
> @seldaek - http://seld.be
>
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/4d133796-3988-4176-94dc-8ce53f034c0d%40googlegroups.com
> <https://groups.google.com/d/msgid/php-fig/4d133796-3988-4176-94dc-8ce53f034c0d%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.


Jordi Boggiano

unread,
Nov 25, 2016, 8:14:00 AM11/25/16
to php...@googlegroups.com
Regarding decrement below zero.. IMO it goes in the negatives but it was
brought up at https://github.com/dragoonis/psr-simplecache/issues/2 that
Memcached doesn't support that for example.

Regarding TTL, I don't care much for DateInterval either but I think it
carried over from PSR-6, and well yes the code is a bit ugly but then
again it's 5 lines to have in a given cache implementation so that
people can use DateInterval if they so wish.. Doesn't seem like a huge
cost to keep the use case possible?

I'll try and get to your other email (novel? :P) later.

Cheers

On 25/11/2016 14:01, Rasmus Schultz wrote:
> One, and one last minor thing... regarding the DateInterval overload for
> $ttl in set() ... well ... why?
>
> Everyone is going to have to write ugly code to convert these into seconds.
>
> Ironically, the answer is first thing that auto-completes on google as
> soon as you type in "dateinterval", but.... copy/pasting this garbage
> everywhere, well, why?
>
> Being able to specify the TTL as DateInterval is just a clumsy,
> round-about way to pass an integer argument, is it not?
>
>
> |$seconds = ($delta->s)+($delta->i *60)+($delta->h *60*60)+($delta->d
> *60*60*24)+($delta->m *60*60*24*30)+($delta->y *60*60*24*365);|
>
>
>
> On Friday, November 25, 2016 at 1:46:23 PM UTC+1, Rasmus Schultz wrote:
>
> Oh, also - a minor question about the decrement() method. Does it go
> into negative when you hit zero, or does it return false, or what?
>
> On Wednesday, November 16, 2016 at 3:22:20 PM UTC+1, Jordi Boggiano
> wrote:
>
> Heya,
>
> We believe PSR-16, Simple Cache, is now ready for final review. As
> coordinator, I hereby open the mandatory review period prior to
> a formal
> acceptance vote; voting will begin no earlier than December 1st,
> 2016.
>
> Here are links to the most current version and its meta document:
>
> https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md
> <https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md>
>
>
> https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md
> <https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md>
>
>
>
> The package containing the interfaces is there:
>
> https://github.com/php-fig/simplecache
> <https://github.com/php-fig/simplecache>
>
>
> The latest important changes to the interfaces can be found at:
>
> https://github.com/php-fig/simplecache/releases/tag/0.2.0
> <https://github.com/php-fig/simplecache/releases/tag/0.2.0>
>
>
> And FWIW, Scrapbook already provides a PSR-16 implementation in its
> upcoming release:
> https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php
> <https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php>
>
>
>
> Thanks for your time reviewing!
>
> Cheers
>
> --
> Jordi Boggiano
> @seldaek - http://seld.be
>
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/4d133796-3988-4176-94dc-8ce53f034c0d%40googlegroups.com
> <https://groups.google.com/d/msgid/php-fig/4d133796-3988-4176-94dc-8ce53f034c0d%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.


Rasmus Schultz

unread,
Nov 25, 2016, 8:42:36 AM11/25/16
to php...@googlegroups.com
Regarding TTL, I don't care much for DateInterval either but I think it carried over from PSR-6

Yet, it doesn't have to - this can be done once in the adapter, rather than every implementation doing it internally. Reduces the margin for bugs.

I don't know anyone who's ever used DateInterval, ever. Seems pointless to burden everyone for an unlikely edge-case? DateInterval seems to have been created for the sole purpose of parsing that string-format. It has no other value, as far as I can tell...

I like consistent interfaces, I guess. Overloading is not my thing.


To post to this group, send email to php...@googlegroups.com

--
Jordi Boggiano
@seldaek - http://seld.be

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/4aed6d6e-192e-eea5-6744-a64a19383507%40seld.be.

Nicolas Grekas

unread,
Nov 25, 2016, 11:45:04 AM11/25/16
to php...@googlegroups.com
Hi all,

Regarding TTL, I don't care much for DateInterval either but I think it carried over from PSR-6

I'm all for keeping DateInterval asis, because it will help writing PSR-6 bridges.

The 5-6 lines snippet you gave Rasmus is actually a one-liner in Symfony, where we deal with absolute timestamps at this stage:
https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Cache/CacheItem.php#L90


About having a "never expires" TTL, it doesn't exist in PSR-6, so that would create a de facto incompatibility with it.
Also, since a cache has no requirement for actually storing an item forever, this would mislead users into thinking that such "never expire" items are safely stored forever in the storage.
Which is actual not desired nor desirable for a cache backend (see memcache LRU). Thus, I'm -1 personally on this proposal.

In order to help review PSR-16 on actual code, I just wrote this (unreviewed nor tested yet) implementation of it for Symfony Cache:
https://github.com/symfony/symfony/pull/20636

Here are my comments based on this work (random order):

On CounterInterface:
  • the draft doesn't say what happens when $key is invalid. I guess the same exception as PSR-6. Should be written?
  • nor does it say when $step is not an integer (return false? throw something?)
  • what should happen when $key already exists in the storage by it not "incrementable"? (Redis INCR fails, I didn't check apcu) => return false ? throw ? erase and store $step? other ?
On CacheInterface:
  • doesn't say what happens when $key is invalid. I guess the same exception as PSR-6. Should be written?

Thanks to everyone involved!

Nicolas

Nicolas Grekas

unread,
Nov 25, 2016, 3:09:30 PM11/25/16
to php...@googlegroups.com
On CacheInterface:
  • doesn't say what happens when $key is invalid. I guess the same exception as PSR-6. Should be written?


I missed adding one note here: the fact that getMultiple returns *all* keys, even cache misses, makes it impossible to (efficiently) implement a PSR-16 to PSR-6 bridge, because it makes it impossible to detect cache misses.
when given an array, apcu_fetch for example has this other behavior of returning only the "hit", so it doesn't suffer from this.
Could this be worth considering for a change?

Nicolas

Nicolas Grekas

unread,
Nov 26, 2016, 4:08:28 AM11/26/16
to php...@googlegroups.com
Hi all,

as posted yesterday, I gave PSR-16 a try in Symfony Cache (https://github.com/symfony/symfony/pull/20636).
This resulted is a number of comments that I summarized in a PR on the FIG's github repo:
https://github.com/php-fig/fig-standards/pull/846

Here are the collected issues/questions:

On CacheInterface:
- doesn't say what happens when $key is invalid => the same exception as PSR-6?
- the fact that `getMultiple` returns *all* keys, even cache misses, makes it impossible to (efficiently) implement a PSR-16 to PSR-6 bridge, because it makes it impossible to detect cache misses. When given an array, `apcu_fetch` for example has this other behavior of returning only the "hit", so it doesn't suffer from this. Could this be worth considering?
- accepting `Traversable` for `*Multiple` methods is not consistent with PSR-6 which only takes arrays as arguments
- returning `array` for `getMultiple` is not consistent with PSR-6 `getItems` which returns `array|Traversable`
- some methods return `void` when they could return `bool` => this is both inconsistent with some other methods, and with PSR-6

On CounterInterface:
- the draft doesn't say what happens when $key is invalid => the same exception as PSR-6?
- nor does it say what happens when $step is not an integer => return false? throw something?
- what should happen when $key already exists in the storage but is not "incrementable/integer"? (Redis INCR fails, I didn't check apcu) => return false? throw? erase and store $step? other?
- atomicity misses a normative MUST or SHOULD.

About exceptions:
- if the PSR is going to document when exceptions should be thrown, then it should either define new exception classes or reuse those from PSR-6
- reusing exceptions defined in PSR-6 would look the most sensible to me
- yet, they are currently not in the same namespace. But: couldn't all these new interfaces move in the Psr\Cache namespace (thus releasing them as psr/cache 1.1 on packagist?)

Best regards,
Nicolas

Larry Garfield

unread,
Nov 26, 2016, 9:39:00 AM11/26/16
to php...@googlegroups.com
Notes in no particular order, most of them fairly minor/easy to fix:

* Typo in the Expiration definition. " This it calculated" should be
"This is calculated". It looks like that is a typo in PSR-6, too, which
we ought to fix. :-)

* " If a negative or zero TTL is provided, the item MUST be deleted from
the cache if it exists, as it is expired already." - We discussed this a
bit at phpWorld, though I don't recall the exact conclusion. I think we
decided that this is already implicit in PSR-6; making it explicit here
is probably unnecessary, but not harmful.

* In Cache Miss, make null a code snippet with `null`.

* The definition of Cache Hit appears to be missing. Is that
deliberate, or an oversight?

* Is there a reason the "Data" section was not borrowed from PSR-6? I'm
assuming all of the same logic applies to PSR-16, so it should either be
duplicated like the definition section is or both should be omitted and
refer to PSR-6 explicitly.

* Some docblock lines end in a period. Others don't. Please standardize
on including the period universally.

* delete() should have a meaningful return, no? Even set() has one, and
in PSR-6 it returns a boolean.

* Ibid for clear().

* getMultiple() accepts array|Traversble, but returns an array. I would
have expected the other way around; accept an array of short strings,
return a traversable of "stuff".

* array|Traversable should be array|\Traversable, or maybe iterable.

* On has(), "Identify if an item is in the cache" should probably be
"Determines if an item is in the cache."

* I don't know that there's an official standard on verbage for
docblocks, but I would encourage following the action-style. That is,
read as though it begins with "this method..." Eg, "This method...
Persists a set of key/value pairs"; "This method... deletes multiple
cache items..."; etc. Currently the verb tenses are inconsistent.

* For increment/decrement, returning "value or false" is an
anti-pattern. It's a PHP language anti-pattern, but still an
anti-pattern. Don't do that. If something breaks, throw an exception
because the data is now invalid anyway.

* And the only major point: I do not think the CounterInterface belongs
here. There's plenty of use cases for an atomic counter that are not
part of a cache; remember a cache could get wiped at any time and the
application must continue to function. Sometimes wiping a counter is
OK, other times it's totally not. That a cache is used for that is an
implementation detail.

I would instead recommend splitting CounterInterface off to its own
(small) PSR. I have no problem with small PSRs if they cover their
target case adequately. Someone could certainly then implement both
CounterInterface and SimpleCache\CacheInterface (or CounterInterface and
CacheItemPoolInterface if they were so inclined) and lose nothing; or
they could implement it on a persistent backend of some sort.

--Larry Garfield

On 11/16/2016 03:22 PM, Jordi Boggiano wrote:
> Heya,
>
> We believe PSR-16, Simple Cache, is now ready for final review. As
> coordinator, I hereby open the mandatory review period prior to a formal
> acceptance vote; voting will begin no earlier than December 1st, 2016.
>
> Here are links to the most current version and its meta document:
>
> https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md
>
>
> The latest important changes to the interfaces can be found at:
>
> https://github.com/php-fig/simplecache/releases/tag/0.2.0
>
>
> And FWIW, Scrapbook already provides a PSR-16 implementation in its
> upcoming release:
> https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php
>
>

Chuck Burgess

unread,
Nov 26, 2016, 11:47:51 AM11/26/16
to php...@googlegroups.com
I agree with Larry about the CounterInterface being worthy of its own PSR.  I also agree about the boolean returns that match with PSR-6, as mismatching them with voids seems like it would at least be problematic in bridging the behavior with -6.
On Wed, Nov 16, 2016 at 8:22 AM, Jordi Boggiano <j.bog...@seld.be> wrote:
Heya,

We believe PSR-16, Simple Cache, is now ready for final review. As
coordinator, I hereby open the mandatory review period prior to a formal
acceptance vote; voting will begin no earlier than December 1st, 2016.

Here are links to the most current version and its meta document:

https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md

https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md


The package containing the interfaces is there:

https://github.com/php-fig/simplecache


The latest important changes to the interfaces can be found at:

https://github.com/php-fig/simplecache/releases/tag/0.2.0


And FWIW, Scrapbook already provides a PSR-16 implementation in its upcoming release: https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php


Thanks for your time reviewing!

Cheers
--
Jordi Boggiano
@seldaek - http://seld.be

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Jordi Boggiano

unread,
Nov 27, 2016, 8:56:58 AM11/27/16
to php...@googlegroups.com
On 25/11/2016 11:21, Rasmus Schultz wrote:
> Assuming I understand the concept correctly, I would *not* expect a
> cache-instance to flush the entire server, but rather to flush only the
> collection represented by the cache-instance.
>
> Doctrine's cache-abstraction includes the concept of "namespaces", which
> equate to collection IDs - but here the distinction is clear, since it
> includes two distinct methods for clearing a collection with deleteAll()
> vs clearing the entire server with flush().
>
> With PSR-16, there is only method, flush(), so it's extremely important
> we understand what precisely the scope of a cache-instance is: a entire
> server, or a collection on a server?

As I understand what you said, PSR-16 represents a cache server, and
flush() would wipe everything on there. The reason IMO is that clearing
the namespace is very inefficient as if the cache backend doesn't have a
concept of namespacing you are forced to iterate over all keys, or keep
track of all keys you write.

I would generally not expect a library I give a Cache to to call
flush(), because that's kinda crazy for most things if you wanna do
invalidation you do it per item you don't blow the whole cache, or at
least that should be an application developer decision..

What I typically do is defining multiple cache instances using redis
databases for "namespacing", so that the keys can not possibly conflict,
and flushing one db doesn't impact any other db. That is maybe not
possible with Memcached, I have no idea.

Jordi Boggiano

unread,
Nov 27, 2016, 9:14:20 AM11/27/16
to php...@googlegroups.com
Thanks for all the feedback!

On 26/11/2016 10:08, Nicolas Grekas wrote:
> On CacheInterface:
> - doesn't say what happens when $key is invalid => the same exception as
> PSR-6?

I guess yes we have to take that over for compatibility. Sounds reasonable.

> - the fact that `getMultiple` returns *all* keys, even cache misses,
> makes it impossible to (efficiently) implement a PSR-16 to PSR-6 bridge,
> because it makes it impossible to detect cache misses. When given an
> array, `apcu_fetch` for example has this other behavior of returning
> only the "hit", so it doesn't suffer from this. Could this be worth
> considering?

IMO this kinda goes in the simplicity category, which is why I still
think enforcing an array return value vs a traversable would also be
simpler.

Using getMultiple() basically can be either:

if ($result['lala'] === null) { ... }

or having to iterate over results to check if it was in it, or having to
use iterator_to_array + if (!isset($result['lala']) { ... }

I find the former much easier, it's less smart (i.e. less surprising)
and possibly a tiny bit less performant if the cache implementation has
to check for missing keys and initialize them to null, but we're talking
really minor differences here in terms of perf.

> - accepting `Traversable` for `*Multiple` methods is not consistent with
> PSR-6 which only takes arrays as arguments

Agreed I think we can remove this..

> - returning `array` for `getMultiple` is not consistent with PSR-6
> `getItems` which returns `array|Traversable`

See 2 points above. I think array only would be best. If it's wrapping a
PSR-6 pool it can just normalize that with iterator_to_array()

> - some methods return `void` when they could return `bool` => this is
> both inconsistent with some other methods, and with PSR-6

Thanks, makes sense.

> On CounterInterface:
> - the draft doesn't say what happens when $key is invalid => the same
> exception as PSR-6?

I'd say so.

> - nor does it say what happens when $step is not an integer => return
> false? throw something?

I'd say InvalidArgumentException there as well as it's misuse and not a
cache error.

> - what should happen when $key already exists in the storage but is not
> "incrementable/integer"? (Redis INCR fails, I didn't check apcu) =>
> return false? throw? erase and store $step? other?

That's a backend error which is usually suppressed as if there was a
cache miss, but here people are going to expect a number back so not
sure if returning false is great (c.f strpos-style common mistakes..).
It is a kind of misuse so maybe throwing here is better?

> - atomicity misses a normative MUST or SHOULD.

I'd say MUST otherwise it's kind of a pointless feature.

> About exceptions:
> - if the PSR is going to document when exceptions should be thrown, then
> it should either define new exception classes or reuse those from PSR-6
> - reusing exceptions defined in PSR-6 would look the most sensible to me
> - yet, they are currently not in the same namespace. But: couldn't all
> these new interfaces move in the Psr\Cache namespace (thus releasing
> them as psr/cache 1.1 on packagist?)

That's an interesting idea, but also kinda confusing for users because
Psr\Cache would suddenly contain a Psr\Cache\Cache which sounds like the
thing to use, but also the Pool.. So maybe best to just duplicate the
InvalidArgumentException/CacheException into SimpleCache namespace.

Jordi Boggiano

unread,
Nov 27, 2016, 9:28:41 AM11/27/16
to php...@googlegroups.com
I'll try to address all formatting/wording stuff in a unified PR later,
thanks.

On 26/11/2016 15:38, Larry Garfield wrote:
> * getMultiple() accepts array|Traversble, but returns an array. I would
> have expected the other way around; accept an array of short strings,
> return a traversable of "stuff".

See my reply to Nicolas Grekas about this, I'd be curious to hear your
thoughts there, to keep it in the same thread.

> * For increment/decrement, returning "value or false" is an
> anti-pattern. It's a PHP language anti-pattern, but still an
> anti-pattern. Don't do that. If something breaks, throw an exception
> because the data is now invalid anyway.

I'd tend to agree there, as I just replied to Nicolas as well.

> * And the only major point: I do not think the CounterInterface belongs
> here. There's plenty of use cases for an atomic counter that are not
> part of a cache; remember a cache could get wiped at any time and the
> application must continue to function. Sometimes wiping a counter is
> OK, other times it's totally not. That a cache is used for that is an
> implementation detail.
>
> I would instead recommend splitting CounterInterface off to its own
> (small) PSR. I have no problem with small PSRs if they cover their
> target case adequately. Someone could certainly then implement both
> CounterInterface and SimpleCache\CacheInterface (or CounterInterface and
> CacheItemPoolInterface if they were so inclined) and lose nothing; or
> they could implement it on a persistent backend of some sort.

Yup.. I think this might be a good thing indeed. Curious to hear from
Paul on this one but I'd tend to +1.

Nicolas Grekas

unread,
Nov 27, 2016, 11:07:26 AM11/27/16
to php...@googlegroups.com
Thanks for the answer Jordi,

I fine with your answers! Just a few notes:


IMO this kinda goes in the simplicity category, which is why I still think enforcing an array return value vs a traversable would also be simpler.

Understood.

Then I'd like to suggest to add a second `$default = null` argument to getMultiple(). That would be consistent with get(), and allow detecting cache misses if really required, by e.g. providing an object there and check the resulting values identities.

 
- returning `array` for `getMultiple` is not consistent with PSR-6
`getItems` which returns `array|Traversable`

See 2 points above. I think array only would be best. If it's wrapping a PSR-6 pool it can just normalize that with iterator_to_array()

No strong opinion on this on my side.


- what should happen when $key already exists in the storage but is not
"incrementable/integer"? (Redis INCR fails, I didn't check apcu) =>
return false? throw? erase and store $step? other?

That's a backend error which is usually suppressed as if there was a cache miss, but here people are going to expect a number back so not sure if returning false is great (c.f strpos-style common mistakes..). It is a kind of misuse so maybe throwing here is better?

I think throwing here is fine, because it would really mean that the app messed up with its cache keys.

 
couldn't all these new interfaces move in the Psr\Cache namespace (thus releasing them as psr/cache 1.1 on packagist?)

That's an interesting idea, but also kinda confusing for users because Psr\Cache would suddenly contain a Psr\Cache\Cache which sounds like the thing to use, but also the Pool.. So maybe best to just duplicate the InvalidArgumentException/CacheException into SimpleCache namespace.

May I suggest to name it Psr\Cache\SimpleCacheInterface (and release it as psr/cache 1.1?)
This would make the most sense to me.

Cheers,
Nicolas

Rasmus Schultz

unread,
Nov 27, 2016, 12:20:42 PM11/27/16
to php...@googlegroups.com
As I understand what you said, PSR-16 represents a cache server, and flush() would wipe everything on there.

I find this answer highly problematic, because that means that there is *no* concept to support back-ends that can (efficiently or not) support multiple collections.

> The reason IMO is that clearing the namespace is very inefficient as if the cache backend doesn't have a concept of namespacing you are forced to iterate over all keys, or keep track of all keys you write.

That's not entirely correct.

Whether or not a back-end supports multiple collections, and whether or not that affects performance, is completely dependent on the back-end.

For example, a file-based cache is no faster or slower, and can support the concept of multiple collections easily, e.g. by simply mapping each instance to a different subfolder.

The same is likely true for a lot of back-ends.

The efficiency question depends entirely on the back-end and it's capabilities, configuration, etc.

I think it's hugely problematic to say that this a cache-instance represents a server, because that leaves no room for a collection-concept, short of building some sort of collection-facility as a layer over a cache-instance - but that's hugely problematic, since, for example, in the case of a file-based cache, this *will* make it very inefficient, e.g. will *have* to store and enumerate keys, which will be much slower (and much less organized) than simply designating a dedicated root-folder at construction.

Also, defining the abstraction as representing a server, means that, by definition, everyone *does* have to worry about key collisions, e.g. everyone must "namespace" everything, everywhere, always.

It also means, as you mentioned, that you don't really expect consumer code to call clear() ... which means, in other words, that a (simple, efficient) means of clearing the cache isn't really effectively something this abstraction offers as a consumer-facing feature at all.

I would very much like to see the abstraction defined as representing a cache-collection instead, because, as far as I can figure, there is no other way to have simple, efficient collection-support.

A collection, in that case, *may* be an entire server, but that's going to depend on your use-case.

Let's consider two real-world examples: a simple, file-based cache, which does have the capacity for multiple collections via multiple root-folders, and an APC back-end, which doesn't have built-in support for multiple collections on a single instance.

In the case of a file-based cache, server-abstraction as the concept doesn't really make any sense, because there's no reason you would want multiple instances of a file-based cache to also (for example) clear() the contents of other instances - you also would not expect such a cache to have key-collisions. I have already implemented a file-based PSR-16 cache, and it's only natural to have a constructor that takes a $root_path, which naturally results in multi-collection semantics. If I had to implement it with server-semantics, I would need a constructor that takes something like a $file_store object as argument and delegates all operations to a "cache server", e.g. calling clear() would clear all instances of the file-store. That would be extremely unnatural and impractical.

For an APC back-end, there would be numerous ways to implement that, and each would have different performance characteristics.

For example, you could have a simple APC-based implementation, which writes to a dedicated APC instance. With server-based semantics, having multiple instances of such a cache doesn't make sense at all, since one instance would effectively clear() the contents of all other instances - in this case, what you should do, is have a *single* instance shared between all consumers, since that's effectively the functionality you'd get from having multiple instances anyway. In other words, it also naturally has collection-semantics, just that there's only one collection. (and there may well be use-cases for that, it's dependent on the needs of the project.)

Another example would be an APC-based implementation that trades off some performance by doing collection-management, but allows for multiple collections on the same server. There are definitely use-cases for that, e.g. hosted projects on servers that only offer one APC instance to each client.

Bottom line: I just don't think a server-abstraction as an isolated concept makes sense, because it implies that everyone should expect key-collisions, side-effects from calling clear(), and other practical problems.

A collection-abstraction is much simpler to work with, and doesn't prevent you from implementing server-*based* collections - but the correct thing to do, in that case, is bootstrap your project to use the same collection-instance, *understanding* that key-collisions may occur, and that clear() will of course clear the entire collection, even if multiple consumers are using the same collection.

Please do consider this very carefully.

This is *not* just a matter of quibbling over words - it completely changes the meaning of the abstraction, the expectations for a consumer, implementation strategies, and so on.

A server-abstraction *precludes* implementations that support multiple collections - a clear() method, by definition, would clear the contents of the *server*.

Compare this with a collection-abstraction, where a clear() method, by definition, clears the contents of the *collection*.

The latter does *not* prevent you from having a collection that happens to be a server.

The former *does* prevent you from having a server that supports multiple collections, which just isn't the reality we have.


--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Larry Garfield

unread,
Nov 27, 2016, 1:33:47 PM11/27/16
to php...@googlegroups.com
On 11/27/2016 06:20 PM, Rasmus Schultz wrote:
As I understand what you said, PSR-16 represents a cache server, and flush() would wipe everything on there.

I find this answer highly problematic, because that means that there is *no* concept to support back-ends that can (efficiently or not) support multiple collections.

*snip*


A server-abstraction *precludes* implementations that support multiple collections - a clear() method, by definition, would clear the contents of the *server*.

Compare this with a collection-abstraction, where a clear() method, by definition, clears the contents of the *collection*.

The latter does *not* prevent you from having a collection that happens to be a server.

The former *does* prevent you from having a server that supports multiple collections, which just isn't the reality we have.

I largely agree with Rasmus here, although the difference is very subtle and likely no more than one or two words in the spec.

PSR-6 used the "pool" concept rather than "server" specifically for this reason; each "pool" is a separate logical namespace independent of any other pool, and two pool objects should not interact.  They could both be backed by a file system (separate directories), or by the same SQL database connection (separate tables), or entirely separate Redis servers, or the same Redis server with automatic prefixing... that's all an implementation detail.  At a logical level they're independent collections.

PSR-16 should follow the same assumption.  In practice I don't think the spec need change for that, or if it does only by a word or two somewhere when discussing what the object represents.

Disclaimer: I am largely approaching PSR-16 as a "streamlined" interface atop PSR-6, via a standardized bridge, as I expect that to be the typical use case.  For that reason, most underlying semantics can and should be borrowed from PSR-6 directly, as we already figured those out at length and those aren't the parts people had issues with. :-)  So my default position on most questions for PSR-16 is "do as PSR-6 does, unless there's a compelling streamlining reason to do otherwise."  I think that will give the most usable and easiest to implement end-result.

--Larry Garfield

Larry Garfield

unread,
Nov 27, 2016, 1:45:17 PM11/27/16
to php...@googlegroups.com
On 11/27/2016 05:07 PM, Nicolas Grekas wrote:
Thanks for the answer Jordi,

I fine with your answers! Just a few notes:


IMO this kinda goes in the simplicity category, which is why I still think enforcing an array return value vs a traversable would also be simpler.

Understood.

Then I'd like to suggest to add a second `$default = null` argument to getMultiple(). That would be consistent with get(), and allow detecting cache misses if really required, by e.g. providing an object there and check the resulting values identities.

 
- returning `array` for `getMultiple` is not consistent with PSR-6
`getItems` which returns `array|Traversable`

See 2 points above. I think array only would be best. If it's wrapping a PSR-6 pool it can just normalize that with iterator_to_array()

No strong opinion on this on my side.

If the concern here is PSR-6 compatibility, bear in mind that since PSR-6 uses a CacheItem object iterator_to_array() won't work.  Additionally, since it could return either an array or traversable, iterator_to_array() cannot be called blindly anyway.  I see two ways that the bridge could work:

public function getMultiple(array $keys) : iterable {
  foreach ($this->pool->getItems($keys) as $item) {
    yield $item->getKey() => $item->get();
  }
}

public function getMultiple(array $keys) : array {
  $result = [];
  foreach ($this->pool->getItems($keys) as $item) {
    $result[$item->getKey()] = $item->get();
  }
  return $result;
}

(Note: Above is entirely untested; I probably made some stupid syntax error.)

In both cases, a cache miss will result in a null entry as Niklas is asking for.  However, a complete cache miss would result in an empty array/iterator, which is how PSR-6 behaves.  This also obviates the need for a $default parameter.

My preference is to follow PSR-6 and allow an iterable for memory safety and consistency (if someone wants an array they can then call iterator_to_array() safely), but I won't make my vote contingent on that.

--Larry Garfield

Rasmus Schultz

unread,
Nov 27, 2016, 1:45:35 PM11/27/16
to php...@googlegroups.com

> PSR-6 used the "pool" concept rather than "server" specifically for this reason; each "pool" is a separate logical namespace independent of any other pool, and two pool objects should not interact.  They could both be backed by a file system (separate directories), or by the same SQL database connection (separate tables), or entirely separate Redis servers, or the same Redis server with automatic prefixing... that's all an implementation detail.  At a logical level they're independent collections.

Yeah, this perfectly summarizes what I managed to put in way too many words. Thanks, Larry :-)


--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.

Jordi Boggiano

unread,
Nov 27, 2016, 3:56:03 PM11/27/16
to php...@googlegroups.com
On 27/11/2016 19:45, Rasmus Schultz wrote:
>> PSR-6 used the "pool" concept rather than "server" specifically for
> this reason; each "pool" is a separate logical namespace independent of
> any other pool, and two pool objects should not interact. They could
> both be backed by a file system (separate directories), or by the same
> SQL database connection (separate tables), or entirely separate Redis
> servers, or the same Redis server with automatic prefixing... that's all
> an implementation detail. At a logical level they're independent
> collections.
>
> Yeah, this perfectly summarizes what I managed to put in way too many
> words. Thanks, Larry :-)

Good to see I can skip the book you wrote in the previous email because
I'm a bit short on time atm ;)

I hear from Nicolas Grekas that the way PSR-6 does it is fine and
generally not an impl problem so I guess I'm fine treating every "Cache"
as a pool, I agree it does make it easier to interop and makes it
possible for libs to use flush() without wreaking havoc.

I'd be very happy if you or Larry could work on a spec PR that does this
fine tuning of words though as I am kinda swamped..

Rasmus Schultz

unread,
Nov 27, 2016, 3:57:53 PM11/27/16
to php...@googlegroups.com

We're already very committed to PSR-16 at work, so I should be able to squeeze that in - will see about getting that done in the morning :-)


--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.

Paul Dragoonis

unread,
Nov 27, 2016, 4:13:44 PM11/27/16
to php...@googlegroups.com
Hey all,
  1. CounterInterface will be dropped from PSR-16 and I will split it off onto a separate PSR, which can be generically used in other PSRs or implementations at will.

  2. SimpleCache will throw InvalidArgumentException from the SimpleCache namespace (not from the PSR-6 Cache namespace)

  3. The typehint array|Traversable will remain on all existing methods. This allows for an extensible implementation around this PSR. This also happens to align with PSR-6 which is a bonus.

  4. The return value of getMultiple() will contain all keys passed, even if that key is not found. This also happens to align with PSR-6 which is a bonus.
Many thanks,
Paul

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Rasmus Schultz

unread,
Nov 28, 2016, 3:51:26 AM11/28/16
to php...@googlegroups.com
One more question, guys.

What about garbage collection?

I know that some cache-servers may take care of this automatically, but for something like a file-based cache, it needs to get triggered.

Is it just left up to each implementation to take care of this in whatever way they need to?


Jordi Boggiano

unread,
Nov 28, 2016, 4:00:54 AM11/28/16
to php...@googlegroups.com
On 28/11/2016 09:51, Rasmus Schultz wrote:
> What about garbage collection?
>
> I know that some cache-servers may take care of this automatically, but
> for something like a file-based cache, it needs to get triggered.
>
> Is it just left up to each implementation to take care of this in
> whatever way they need to?

Yes :) This is an application concern IMO, much like the management of
multiple cache pools, etc.

If you read again my post from 4 years ago [1], PSRs I find are largely
beneficial for libraries and not for frameworks/applications.
Applications are in control, but libraries have no control and are
dropped in random contexts. It kinda bums me out that many still don't
seem to understand that (or just don't see it that way?).

It's unfortunate that FIG has framework in its name because it is highly
misleading, but down the line Framework-level Interoperability means
having interoperable libraries more than frameworks being able to
interact with each other.

[1] https://seld.be/notes/one-logger-to-rule-them-all

Larry Garfield

unread,
Nov 28, 2016, 1:07:25 PM11/28/16
to php...@googlegroups.com

On Nov 27, 2016 10:13 PM, Paul Dragoonis <drag...@gmail.com> wrote:

> The typehint array|Traversable will remain on all existing methods. This allows for an extensible implementation around this PSR. This also happens to align with PSR-6 which is a bonus.

The return types only, right? Passing in a traversable of array keys to getMultiple makes little sense to me, and is out of alignment with PSR-6.

Otherwise these changes all sound good to me. Thanks!

--Larry Garfield

Daniel Hunsaker

unread,
Nov 28, 2016, 6:14:24 PM11/28/16
to PHP Framework Interoperability Group
On Sunday, November 27, 2016 at 9:07:26 AM UTC-7, Nicolas Grekas wrote:
 
couldn't all these new interfaces move in the Psr\Cache namespace (thus releasing them as psr/cache 1.1 on packagist?)

That's an interesting idea, but also kinda confusing for users because Psr\Cache would suddenly contain a Psr\Cache\Cache which sounds like the thing to use, but also the Pool.. So maybe best to just duplicate the InvalidArgumentException/CacheException into SimpleCache namespace.

May I suggest to name it Psr\Cache\SimpleCacheInterface (and release it as psr/cache 1.1?)
This would make the most sense to me.

This suggestion would make a lot more sense if PSR-16 was actually intended to *replace* PSR-6.  My understanding is that -16 is merely a simplified approach that can be used alongside -6, not an attempt to replace it outright.  Folding this PSR into `psr/cache` would have a number of side effects, including pulling in interfaces that aren't actually used, decreased clarity about which are which, increased complexity of documentation (gotta look at two separate PSRs to understand what's going on), and so on.  Not to mention the confusion that would follow a version bump (specifically this one, but also potentially others, if bugfixes are applied later), such as: "So is PSR-6 superceded?" "What bugfix caused a version bump?" "Oh, great, now my implementation is out of date..." and so forth.

This *could* be done, sure, but I believe both PSR-6 and PSR-16 are better served having separate repos for their interfaces, despite sharing some interfaces (at least conceptually).

Only feedback I have that I haven't seen already.

Rasmus Schultz

unread,
Nov 29, 2016, 3:52:56 AM11/29/16
to php...@googlegroups.com
This is an application concern IMO, much like the management of multiple cache pools, etc.

Yeah, for some types of cache-servers, flushing expired entries on-demand may not even be a thing - so this is likely outside the scope of what should be interoperable, as this kind of functionality is implementation-specific.

Oh, and here's a simple flat-file cache-implementation:


It's complete, but will of course change with the coming interface updates.

I don't know if there are any other flat implementations of PSR-16 cache out there? I don't see any on Packagist. So this might be helpful as a real-world case.

One other thing, about the documentation and meta... it all sounds like PSR-16 was designed to be a layer on top of PSR-6? It almost sounds as though PSR-16 *depends* upon PSR-6?

That seems really wrong. I mean, PSR-16 is complete within it's own scope, and has no dependency on PSR-6 whatsoever - it's perfectly feasible to make PSR-16 libraries stand alone.

I think it's great if the meta/doc states that it was designed with PSR-6 compatibility in mind, making it possible to bridge PSR-6 to PSR-16, but both the doc and meta at the moment make it sound like that's it's only purpose...

I personally view it as a simple alternative to PSR-6, not a layer that I'm going to put over it. (I don't want to hide complexity - I want to remove it and simplify.)

Has a PSR-6 to PSR-16 bridge been implemented?


--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.

Jordi Boggiano

unread,
Nov 29, 2016, 8:21:17 AM11/29/16
to php...@googlegroups.com
Yes PSR-16 is meant to live alongside PSR-6, so it has to be reasonably
compatible and yes a bridge has been done
(https://github.com/php-fig/simplecache/commit/13f43ba7f6d5ce37c6c115c26a5f653c2d9c1e18).
I agree it shouldn't sound like it depends on PSR-6 though. If you have
ideas how to clarify the wording PRs are welcome :)

Cheers
> <https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe>.
> To unsubscribe from this group and all its topics, send an email to
> php-fig+u...@googlegroups.com
> <mailto:php-fig%2Bunsu...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> <https://groups.google.com/d/msgid/php-fig/13388408-c187-2738-7940-1084f473be5b%40seld.be>.
>
> For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to php-fig+u...@googlegroups.com
> <mailto:php-fig+u...@googlegroups.com>.
> To post to this group, send email to php...@googlegroups.com
> <mailto:php...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/CADqTB_gx8bysGMiQ5uep7jWE4XS8rCiz9%2BjhypjKWqOPJurZ5A%40mail.gmail.com
> <https://groups.google.com/d/msgid/php-fig/CADqTB_gx8bysGMiQ5uep7jWE4XS8rCiz9%2BjhypjKWqOPJurZ5A%40mail.gmail.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.


Rasmus Schultz

unread,
Nov 29, 2016, 10:58:30 AM11/29/16
to php...@googlegroups.com
ok, will try to put in a PR for that tomorrow :-)




    To post to this group, send email to php...@googlegroups.com
    <mailto:php-fig@googlegroups.com>.

    To view this discussion on the web visit
    https://groups.google.com/d/msgid/php-fig/13388408-c187-2738-7940-1084f473be5b%40seld.be
    <https://groups.google.com/d/msgid/php-fig/13388408-c187-2738-7940-1084f473be5b%40seld.be>.

    For more options, visit https://groups.google.com/d/optout
    <https://groups.google.com/d/optout>.


--
You received this message because you are subscribed to the Google
Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send

To post to this group, send email to php...@googlegroups.com

--
Jordi Boggiano
@seldaek - http://seld.be

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/0b5cb48a-48c9-c8a9-c178-7eafe8c16d78%40seld.be.

Nicolas Grekas

unread,
Nov 29, 2016, 5:05:50 PM11/29/16
to php...@googlegroups.com

Yes PSR-16 is meant to live alongside PSR-6, so it has to be reasonably compatible and yes a bridge has been done (https://github.com/php-fig/simplecache/commit/13f43ba7f6d5ce37c6c115c26a5f653c2d9c1e18).
 
Note that by not sharing the same namespace for exceptions, the actual bridge is going to be much more verbose (even more if `*Multiple` methods are going to accept array|Traversable.)
And converting instances of CacheException (the interface) from one namespace to another is even going to be impossible...

Adrien Crivelli

unread,
Nov 29, 2016, 9:24:48 PM11/29/16
to PHP Framework Interoperability Group
That commit doesn't mention why the bridge has been removed from the source tree. Would you please let us know the reason ? Is it considered out of scope ? Is it living in another package ?

To me it seems it could have been useful, but I may be missing something obvious.

Jordi Boggiano

unread,
Nov 30, 2016, 3:44:50 AM11/30/16
to php...@googlegroups.com
On 30/11/2016 03:24, Adrien Crivelli wrote:
>
> yes a bridge has been done
> (https://github.com/php-fig/simplecache/commit/13f43ba7f6d5ce37c6c115c26a5f653c2d9c1e18
> <https://github.com/php-fig/simplecache/commit/13f43ba7f6d5ce37c6c115c26a5f653c2d9c1e18>).
>
>
>
> That commit doesn't mention why the bridge has been removed from the
> source tree. Would you please let us know the reason ? Is it considered
> out of scope ? Is it living in another package ?
>
> To me it seems it could have been useful, but I may be missing something
> obvious.

It's meant to live in a simple-cache-utils package and not in the "spec"
one.

Larry Garfield

unread,
Nov 30, 2016, 11:10:03 AM11/30/16
to php...@googlegroups.com
On 11/29/2016 02:21 PM, Jordi Boggiano wrote:
> Yes PSR-16 is meant to live alongside PSR-6, so it has to be
> reasonably compatible and yes a bridge has been done
> (https://github.com/php-fig/simplecache/commit/13f43ba7f6d5ce37c6c115c26a5f653c2d9c1e18).
> I agree it shouldn't sound like it depends on PSR-6 though. If you
> have ideas how to clarify the wording PRs are welcome :)
>
> Cheers

I've opened a PR to clarify both the PSR-6 relationship and the "cache
is not a server" point, as they're related:

https://github.com/php-fig/fig-standards/pull/851

--Larry Garfield

Josh Di Fabio

unread,
Dec 1, 2016, 4:24:29 AM12/1/16
to php...@googlegroups.com
> Different CacheInterface instances MAY be backed by the same datastore, but MUST be logically independent.

The second clause seems to be needlessly restrictive and appears to be incompatible with decorators. What is the purpose of this clause?

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/0cf7897f-1334-a7fd-21fb-5bed0e926024%40garfieldtech.com.

Larry Garfield

unread,
Dec 1, 2016, 5:54:56 AM12/1/16
to php...@googlegroups.com
On Thu, Dec 1, 2016, at 03:24 AM, Josh Di Fabio wrote:
> > Different CacheInterface instances MAY be backed by the same datastore, *but
> MUST be logically independent.*
>
> The second clause seems to be needlessly restrictive and appears to be
> incompatible with decorators. What is the purpose of this clause?

If the pools aren't logically independent, their namespaces end up
colliding. They need to be logically distinct, even if they are on the
same physical server. I'm not clear how that is an issue for decorators.

--Larry Garfield

Josh Di Fabio

unread,
Dec 1, 2016, 6:34:09 AM12/1/16
to php...@googlegroups.com
If the pools aren't logically independent, their namespaces end up colliding. They need to be logically distinct, even if they are on the same physical server.

This is an application concern. It's the responsibility of the application to provide CacheInterface instances which are usable and correct in specific contexts based on the nature of the application. Also, why are we talking about pools in a spec which deliberately doesn't define them? It's out of scope.

Currently, the spec appears to state that having multiple cache objects in memory which might overlap logically is invalid. Surely this is an application concern, and out of scope for this spec?

I'm not clear how that is an issue for decorators.

In the following example of a trivial decorator, we have two instances of CacheInterface which are not logically independent. Is this invalid?

class LoggingCache implements CacheInterface
{
    private $cache;
    private $logger;

    ...

    public function set($key, $value, $ttl = null);
    {
        $this->logger->debug("$key was saved to the cache");
        return $this->cache->set($key, $value, $ttl);
    }

    ...
}

How about a cache object which represents a subset of another cache object?

class CacheSubset implements CacheInterface
{
    private $cache;
    private $keyPrefix;

    ...

    public function set($key, $value, $ttl = null);
    {
        return $this->cache->set($this->keyPrefix . $key, $value, $ttl);
    }

    ...
}

Do you consider these examples invalid according to the wording in the spec?

This spec should enable clients to easily work with different cache implementations; I don't understand why the spec needs to start interfering with application concerns.

Does anyone other than Larry have any views on this?

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.

Rasmus Schultz

unread,
Dec 1, 2016, 7:47:49 AM12/1/16
to php...@googlegroups.com
why are we talking about pools in a spec which deliberately doesn't define them? It's out of scope.

I'd say it's the other way around - the PSR-16 cache-abstraction represents a logical collection.

The definition, in my opinion, is perfect - if we don't define what it is, people might assume that the abstraction is a server, in which case they need to concern themselves with key-collisions, accidentally clearing another consumer's cache-entries, and so on.

The goal being simplicity, the abstraction needs to be defined explicitly as being a logical collection, meaning you don't have to worry about key-collisions and such.

A consumer should be able to assume that the cache instance provided to it is intended for it's own use.

Otherwise, we would automatically need a layer on top of PSR-16 from day one, to add things like key-prefixes etc. which increases complexity and may degrade performance.

By defining the concept as being a collection, it becomes up to the application developer to bootstrap an application either using multiple cache-servers, or an implementation that supports multiple namespaces on one server, or in the case of a file-based cache using distinct root-folders, etc.

That's all implementation-specific, but that only works because the concept of a server, for example, is outside the scope of this specification. Some back-ends (file-based) don't even relate with the concept of a server, so this is a very good thing.



To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Josh Di Fabio

unread,
Dec 1, 2016, 9:33:05 AM12/1/16
to php...@googlegroups.com
Thanks for the reply, Rasmus. In principle I think we want the same things. However, I think the wording in the spec is wrong, especially this part:

"Different CacheInterface instances ... MUST be logically independent."

Do you agree that the above clause from the spec makes the following class illegal? If so, should the class be illegal?

class CacheSubset implements CacheInterface
{
    /** @var CacheInterface $cache */
    private $cache;
    private $keyPrefix;

    ...

    public function set($key, $value, $ttl = null);
    {
        return $this->cache->set($this->keyPrefix . $key, $value, $ttl);
    }

    ...
}

Surely it should be valid for an application to do the following, which appears to me to be forbidden by the spec as it stands:

$cache = new FileCache('/tmp/foo');
$configCache = new CacheSubset($cache, $keyPrefix = 'config.');
$dbSchemaCache = new CacheSubset($cache, $keyPrefix = 'db_schema.');
// somewhere else...
$cache->clear();

On Thu, Dec 1, 2016 at 12:47 PM Rasmus Schultz <ras...@mindplay.dk> wrote:
why are we talking about pools in a spec which deliberately doesn't define them? It's out of scope.

I'd say it's the other way around - the PSR-16 cache-abstraction represents a logical collection.

The definition, in my opinion, is perfect - if we don't define what it is, people might assume that the abstraction is a server, in which case they need to concern themselves with key-collisions, accidentally clearing another consumer's cache-entries, and so on.

The goal being simplicity, the abstraction needs to be defined explicitly as being a logical collection, meaning you don't have to worry about key-collisions and such.

A consumer should be able to assume that the cache instance provided to it is intended for it's own use.

This is entirely dictated by the application being configured correctly. If the application incorrectly provides the same cache instance to two unrelated services then things will still break. The line in the spec which I quoted above doesn't change this; it's still necessary for the application to be configured correctly.
 
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+u...@googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Rasmus Schultz

unread,
Dec 2, 2016, 2:26:03 PM12/2/16
to php...@googlegroups.com
Do you agree that the above clause from the spec makes the following class illegal?

Illegal? Heh. No :-)

If it makes sense within your project to bootstrap things that way - assuming you *want* one collection's clear() method to clear all other collections, that's "your problem", so to speak.

I don't know why you'd want that. Dealing with logically independent collections is much safer and simpler.

I wouldn't use that.

But of course you're free to do whatever you want.


To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Rasmus Schultz

unread,
Dec 2, 2016, 2:28:50 PM12/2/16
to php...@googlegroups.com
A better approach to what you're doing is probably a proprietary clear() method on your cache "server" object - that's outside the scope of PSR-16, but of course you're completely free to do that, and it might well be meaningful, e.g. clearing *all* file-cache collections with a single call after a deployment.


To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Paul Dragoonis

unread,
Dec 2, 2016, 4:39:33 PM12/2/16
to php...@googlegroups.com

Cheers for the feedback everyone. I will sit down with Jordi as soon as we're both available (tonight?), to go through everything. Speak soon.

On 27 Nov 2016 14:28, "Jordi Boggiano" <j.bog...@seld.be> wrote:
>
> I'll try to address all formatting/wording stuff in a unified PR later, thanks.
>
>
> On 26/11/2016 15:38, Larry Garfield wrote:
>>
>> * getMultiple() accepts array|Traversble, but returns an array.  I would
>> have expected the other way around; accept an array of short strings,
>> return a traversable of "stuff".
>
>
> See my reply to Nicolas Grekas about this, I'd be curious to hear your thoughts there, to keep it in the same thread.
>
>
>> * For increment/decrement, returning "value or false" is an
>> anti-pattern.  It's a PHP language anti-pattern, but still an
>> anti-pattern.  Don't do that.  If something breaks, throw an exception
>> because the data is now invalid anyway.
>
>
> I'd tend to agree there, as I just replied to Nicolas as well.
>
>
>> * And the only major point: I do not think the CounterInterface belongs
>> here.  There's plenty of use cases for an atomic counter that are not
>> part of a cache; remember a cache could get wiped at any time and the
>> application must continue to function.  Sometimes wiping a counter is
>> OK, other times it's totally not.  That a cache is used for that is an
>> implementation detail.
>>
>> I would instead recommend splitting CounterInterface off to its own
>> (small) PSR.  I have no problem with small PSRs if they cover their
>> target case adequately.  Someone could certainly then implement both
>> CounterInterface and SimpleCache\CacheInterface (or CounterInterface and
>> CacheItemPoolInterface if they were so inclined) and lose nothing; or
>> they could implement it on a persistent backend of some sort.
>
>
> Yup.. I think this might be a good thing indeed. Curious to hear from Paul on this one but I'd tend to +1.


>
>
> Cheers
>
> --
> Jordi Boggiano
> @seldaek - http://seld.be
>

> --
> You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.

> To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.


> To post to this group, send email to php...@googlegroups.com.

> To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/36fad92d-e512-8980-9d82-9c43faa1c4eb%40seld.be.

Alexander Ustimenko

unread,
Dec 5, 2016, 12:41:15 PM12/5/16
to PHP Framework Interoperability Group
Hi Jordi!

I will reply one message per issue.

First that I see in current CacheInterface is `blaMultiple` methods, that seems strange and far-fetched in simple cache interface.

Why do I need to think about blaMultiple when I have `CacheInterface $cache`? It's a simlpe cache with get/set and more complex usage patterns are already in current Cache PSR.

So I suggest to remote remove blaMultiple from CacheInterface into MultipleCacheInterface. Or just remove it from SimpleCache at all.

среда, 16 ноября 2016 г., 21:22:20 UTC+7 пользователь Jordi Boggiano написал:
Heya,

We believe PSR-16, Simple Cache, is now ready for final review. As
coordinator, I hereby open the mandatory review period prior to a formal
acceptance vote; voting will begin no earlier than December 1st, 2016.

Here are links to the most current version and its meta document:

https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache.md

https://github.com/php-fig/fig-standards/blob/1cf169c66747640c6bc7fb5097d84fbafcd00a0c/proposed/simplecache-meta.md


The package containing the interfaces is there:

https://github.com/php-fig/simplecache


The latest important changes to the interfaces can be found at:

https://github.com/php-fig/simplecache/releases/tag/0.2.0


And FWIW, Scrapbook already provides a PSR-16 implementation in its
upcoming release:
https://github.com/matthiasmullie/scrapbook/blob/master/src/Psr16/SimpleCache.php


Thanks for your time reviewing!

Alexander Ustimenko

unread,
Dec 5, 2016, 12:47:52 PM12/5/16
to PHP Framework Interoperability Group
Another issue that we have now in current cache and cache-util is complete missing of null-object.

In Psr/Log we have NullLogger, why we can't have NullCache?

There are situations, when we dont' know 100%, that there or here we need cache. Or we know, that we need cache there, but for some time we can live without it.

Cache could be an optional dependency. It's a bitter thought, but it's a truth. So I suggest to add to Psr/Simple cache default NullCache as just /dev/null or BlackWhole implementation.

Examples:

Same as https://github.com/php-fig/log/blob/master/Psr/Log/NullLogger.php


Use case

Cache as an optional injectable dependency. When class user not provides it -- we take ready NullCache and use it.

Larry Garfield

unread,
Dec 5, 2016, 1:02:42 PM12/5/16
to php...@googlegroups.com
We've decided since PSR-3 that such "stock implementations" do not belong in the spec, but can live in -util libraries.  A NullCache implementation of PSR-6 / PSR-16 would be very welcome for cache-util.
--
You received this message because you are subscribed to the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+u...@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.

Устименко Александр

unread,
Dec 5, 2016, 2:12:43 PM12/5/16
to php...@googlegroups.com
Larry, this approach is overcomplicated.

NullObject of any interface can be implemented in single simple way.

My PRs in OverComplexCache are still open and I dont' believe it would be merged.

So let complex things will be in complex PSRs and simple ones in simple.

As I understand current PSR/Cache is not meet developers needs, so that we have SimpleCache PSR here.





__________________
Alexander Ustimenko
    +7 (952) 918-02-20

To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/b67406ac-5227-456d-a7c3-f65523bf527d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.
To post to this group, send email to php...@googlegroups.com.

Larry Garfield

unread,
Dec 5, 2016, 3:36:58 PM12/5/16
to php...@googlegroups.com
I think you misunderstand.

PSR-6 *does* meet some developer needs.  PSR-16 is to optimize for a narrower-but-common use case.  They complement each other.  That's fine.

Neither PSR-6 nor PSR-16 (nor PSR-7 for that matter) have implementations included in the spec or in the Packagist package.  That's fine.  For basic implementations for which there's no reason for everyone to re-implement them (eg, Null cache), or portions therein, we offer -util packages.  It currently doesn't include a null implementation of PSR-6 or PSR-16.  Adding one would not be difficult and (speaking as the nominal maintainer of the cache-util package) would be very welcome.

--Larry Garfield

Rasmus Schultz

unread,
Dec 6, 2016, 9:39:40 AM12/6/16
to PHP Framework Interoperability Group
Personally, I don't use a null-cache, ever.

The problem with a null-cache, is that it's not actually a cache - it satisfies the interface, but doesn't behave like a cache, so it's not even useful for testing.

I wrote this for testing where I have PSR-16 dependencies:


I've never had a use-case, test or otherwise, where a null-cache actually satisfied the requirement. I would never add caching to something that doesn't require caching, and if it requires caching, a null-cache isn't even a meaningful default. I honestly don't understand they're for, but maybe that's just me ;-)

Matthew Weier O'Phinney

unread,
Dec 6, 2016, 2:32:52 PM12/6/16
to php...@googlegroups.com
On Tue, Dec 6, 2016 at 8:39 AM, Rasmus Schultz <ras...@mindplay.dk> wrote:
> Personally, I don't use a null-cache, ever.
>
> The problem with a null-cache, is that it's not actually a cache - it
> satisfies the interface, but doesn't behave like a cache, so it's not even
> useful for testing.
>
> I wrote this for testing where I have PSR-16 dependencies:
>
> https://github.com/kodus/mock-cache
>
> I've never had a use-case, test or otherwise, where a null-cache actually
> satisfied the requirement. I would never add caching to something that
> doesn't require caching, and if it requires caching, a null-cache isn't even
> a meaningful default. I honestly don't understand they're for, but maybe
> that's just me ;-)

It's a matter of architecture. In many systems I've used and studied,
classes may require a cache to the constructor. However, in
development mode, you may want to ensure the cache is never hit —
perhaps you do not have access to the appropriate cache server, or do
not want to worry about trampling the work other developers are doing,
etc. Alternately, you may want to ensure the business logic _must_ be
hit, instead of the cached results, so that you can trace code
execution. As such, having the ability to have a null cache injected
instead of a version backed by a data store can be quite useful.
> https://groups.google.com/d/msgid/php-fig/ddb02530-5460-4d90-95fa-53a7afc286f6%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.



--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/

FGM

unread,
Dec 30, 2016, 5:19:11 AM12/30/16
to PHP Framework Interoperability Group
Is there any reason why the interface has get/getMultiple set/setMultiple delete/deleteMultiple but only has without hasMultiple ? For the described purpose of cache warming it would make at least as much sense as for the get/set/delete operations, and I could not find a thread discussing this.

Rasmus Schultz

unread,
Dec 30, 2016, 8:48:29 AM12/30/16
to PHP Framework Interoperability Group
hasMultiple() would be dealing with several results, so is the result an AND or OR of the individual results?

I think, if you had something like this, it would need to be two methods: hasAll() for the AND operation and hasAny() for the OR.

Either way, I think that checking for the presence of multiple values is very easy, is not something that is optimized by most back-ends (if any?) and not an extremely common use-case - so maybe burdening every implementation with this is a bit unnecessary?

One other minor issue I've been wondering about is regarding getMultiple() ... I think that the $default argument, and returning cache-keys that do not exist may not be the most useful approach.

In how many cases will you be fetching multiple different values and can meaningfully replace missing *all* of them with the same default?

I think that, in the majority of use-cases, if $default is used with getMultiple() at all, it will be used as a work-around used to identify missing values, rather than to set an actual default - I don't imagine a single default will be very useful for multiple values?

So I would have preferred a signature like getMultiple($keys) and a return-value with missing key for missing values, so you could isset() to check for existence.

This would also be consistent at least with Memcached and any SQL-based back-end. (probably the two most common/popular types of back-end?)

FGM at GMail

unread,
Dec 30, 2016, 1:50:04 PM12/30/16
to php...@googlegroups.com
Good enough answer for me, thanks Rasmus.

To unsubscribe from this group and stop receiving emails from it, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Brad Kent

unread,
Mar 15, 2017, 10:22:09 AM3/15/17
to PHP Framework Interoperability Group
I know I'm late to the party, but what's the use-case for passing a default value to the get method?

If we're using a cache isn't generating/getting the value expensive?
It seems to encourage something boneheaded like: 

$default = someExpensiveOperation();
$myValue = $myCache->get('foo', $default);

I could understand passing a callable that would set the value for a cache miss...

Rasmus Schultz

unread,
Mar 15, 2017, 12:45:22 PM3/15/17
to php...@googlegroups.com
It's a default value in case of a miss - it's there mainly to support an edge-case where someone is caching NULL values, and might need to pass a different default value, so they can tell the difference between a cached NULL-value and an actual miss.

So in your case:

    $default = new stdClass(); // unique object representing a cache-miss

    $myValue = $myCache->get('foo', $default); // might return a cached NULL

    if ($myValue === $default) { // definitely a cache-miss
        $myValue = someExpensiveOperation(); // might return NULL

        $myCache->set('foo', $myValue); // might cache a NULL
    }

At least that's my understanding.


--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/kSj_yVbkwOw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+unsubscribe@googlegroups.com.

To post to this group, send email to php...@googlegroups.com.

Michael Mayer

unread,
Mar 16, 2017, 5:05:58 AM3/16/17
to PHP Framework Interoperability Group
You can use `$default` in conjunction with the Null Object pattern. Whereby you usually don't want to cache Null Objects.

For example for message board users:

class UnknownUser implements User {…} // Null Object Class, providing proper avatar etc.

$unknownUser = new UnknownUser(); // N.B. $unknownUser is created only once, but can be reused multiple times

// somewhere:
$user
= $userCache->get('name of deleted user', $unknownUser);
$view
->render('comment.html', ['user' => $user, …]);

This may make your code less complex, thus easier to read and understand – you do not need `if ($user === null) {…}` after each `->get()`.
Reply all
Reply to author
Forward
0 new messages