问题
I am trying to use different cache system on my environments. I would like to have, for example, Filesystem for dev and memcached for prod.
I am using symfony 3.3.10.
To achieve this, I would like to autowire the CacheInterface as follow:
use Psr\SimpleCache\CacheInterface;
class Api {
    public function __construct(CacheInterface $cache)
    {
        $this->cache = $cache;
    }
}
Here are my configuration files:
config_dev.yml:
framework:
    cache:
        app: cache.adapter.filesystem
config_prod.yml:
framework:
    cache:
        app: cache.adapter.memcached
        ...
Here is the error I get:
The error disappears when the FilesystemCache is declared as a service:
services:
    Symfony\Component\Cache\Simple\FilesystemCache: ~
But now I cannot have another cache system for the test environment like NullCache. In fact, I have to declare only one service inheriting from CacheInterface. It is not possible as config_test is using config_dev too.
This is the beginning of services.yml if it can help:
services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false
Any idea on how to autowire different cache system depending on the environment?
EDIT:
Here is the working configuration:
use Psr\Cache\CacheItemPoolInterface;
class MyApi
{
    /**
     * @var CacheItemPoolInterface
     */
    private $cache;
    public function __construct(CacheItemPoolInterface $cache)
    {
        $this->cache = $cache;
    }
}
config.yml:
framework:
    # ...
    cache:
        pools:
            app.cache.api:
                default_lifetime: 3600
services.yml:
# ...
Psr\Cache\CacheItemPoolInterface:
    alias: 'app.cache.api'
回答1:
Even though factory pattern is a good option to solve this kind of problematic, normally you don't need to do that for Symfony cache system. Typehints CacheItemPoolInterface instead:
use Psr\Cache\CacheItemPoolInterface;
public function __construct(CacheItemPoolInterface $cache)
It automatically inject the current cache.app service depending on the active environment, so Symfony does the job for you!
Just make sure to configure the framework.cache.app for each environment config file:
# app/config/config_test.yml
imports:
    - { resource: config_dev.yml }
framework:
    #...
    cache:
        app: cache.adapter.null
services:
    cache.adapter.null:
        class: Symfony\Component\Cache\Adapter\NullAdapter
        arguments: [~] # small trick to avoid arguments errors on compile-time.
As cache.adapter.null service isn't available by default, you might need define it manually.
回答2:
In Symfony 3.3+/4 and 2017/2019 you can omit any config dependency and keep full control of the behavior with factory pattern:
// AppBundle/Cache/CacheFactory.php
namespace AppBundle\Cache;
final class CacheFactory
{
    public function create(string $environment): CacheInterface
    {
        if ($environment === 'prod') {
            // do this
            return new ...;
        }
        // default 
        return new ...;
    }
}
And services.yml of course:
# app/config/services.yml
services:
    Psr\SimpleCache\CacheInterface:
        factory: 'AppBundle\Cache\CacheFactory:create'
        arguments: ['%kernel.environment%']
See more about service factory in Symfony Documentation.
You can read more about this in my Why Config Coding Sucks post.
来源:https://stackoverflow.com/questions/46893809/autowire-symfony-cacheinterface-depending-on-environment