title: Symfony 4 services local binding in different environments
body: <p>I have to bind parameters with different values in different environments, and having problems with this.</p>
  
  <p>I was trying this:</p>
  
  <pre><code># config/services.yaml
  services:
      _defaults:
          bind:
              $param: 'param for PROD'
  
  # config/services_dev.yaml
  services:
      _defaults:
          bind:
              $param: 'param for DEV'
  
  # src/Controller/SomeController.php
  class MyController extends AbstractController
  {
      public function example($param)
      {
          echo $param;
      }
  }
  </code></pre>
  
  <p>But it forces me to have all the services defined in both of <strong>services.yaml</strong> and <strong>services_dev.yaml</strong> files, otherwise it does not work.</p>
  
  <p>I would like to have a <strong>services.yaml</strong> shared for any environment, and only override the custom services/bindings etc, not have two identical files with all services listed in them for changing one binding value.</p>
  
  <hr>
  
  <p>The real problem is that I have to create two http clients (real and a dummy) with same interface, in production load the real one, and in development load the dummy, Symfony 4-s autowiring allows me to inject the interface in a controller and choose which client to use in binding:</p>
  
  <pre><code># config/services.yaml
  services:
      _defaults:
          bind:
              'ClientInterface': '@real_client'
      # More services here...
  
  # config/services_dev.yaml
  services:
      _defaults:
          bind:
              'ClientInterface': '@dummy_client'
      # Here I don't want to have another copy of the services, 
      # but it does not work without them
  
  # Controller
  public function someMethod(ClientInterface $client)
  {
      // ...
  }
  </code></pre>
  
  <p>In Symfony 2 I was able to extend services.yml and in services_dev.yml only define the specific values I wanted to override/add, but in Symfony 4 <strong>services_dev.yaml</strong> can not use services from <strong>services.yaml</strong> and I have to keep my services identical in two different files which is pain. </p>
  
  <p>Anny suggestions?</p>
  
  <p>Thank you.</p>
  
  <hr>
  
  <p>I'm updating the post again with a real example:</p>
  
  <h1>services.yaml</h1>
  
  <pre><code># This file is the entry point to configure your own services.
  # Files in the packages/ subdirectory configure your dependencies.
  
  # Put parameters here that don't need to change on each machine where the app is deployed
  # https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
  parameters:
      locale: 'en'
      app.access_token: '%env(string:APP_ACCESS_TOKEN)%'
      app.aws_version: '%env(string:AWS_VERSION)%'
      app.aws_profile: '%env(string:AWS_PROFILE)%'
      app.aws_region: '%env(string:AWS_REGION)%'
      app.aws_queue_url_creation: '%env(string:AWS_QUEUE_URL_CAMPAIGN_CREATION)%'
      app.aws_queue_url_edition: '%env(string:AWS_QUEUE_URL_CAMPAIGN_EDITION)%'
      app.redis_host: '%env(string:REDIS_HOST)%'
      app.redis_port: '%env(string:REDIS_PORT)%'
  
  services:
      # default configuration for services in *this* file
      _defaults:
          autowire: true      # Automatically injects dependencies in your services.
          autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
          public: false       # Allows optimizing the container by removing unused services; this also means
                              # fetching services directly from the container via $container-&gt;get() won't work.
                              # The best practice is to be explicit about your dependencies anyway.
          bind:
              App\Service\MessageSenderServiceInterface: '@App\Service\MessageSenderSqsService'
  
      # makes classes in src/ available to be used as services
      # this creates a service per class whose id is the fully-qualified class name
      App\:
          resource: '../src/*'
          exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
  
      # controllers are imported separately to make sure services can be injected
      # as action arguments even if you don't extend any base controller class
      App\Controller\:
          resource: '../src/Controller'
          tags: ['controller.service_arguments']
  
      # add more service definitions when explicit configuration is needed
      # please note that last definitions always *replace* previous ones
  
      # Authenticators
      App\Security\ApiKeyAuthenticator:
          arguments:
              - "%app.access_token%"
  
      # Clients
      App\Client\AwsSqsClient:
          arguments:
              - "%app.aws_version%"
              - "%app.aws_profile%"
              - "%app.aws_region%"
  
      App\Client\RedisClient:
          arguments:
              - "%app.redis_host%"
              - "%app.redis_port%"
  
      # Services
      App\Service\MessageSenderSqsService:
          arguments:
              - '@App\Client\AwsSqsClient'
              - '@App\Client\RedisClient'
              - "%app.aws_queue_url_creation%"
              - "%app.aws_queue_url_edition%"
  
      App\Service\MessageSenderRedisService:
          arguments:
              - '@App\Client\RedisClient'
  </code></pre>
  
  <h1>services_dev.yaml</h1>
  
  <pre><code>imports:
      - { resource: services.yaml }
  
  services:
      # default configuration for services in *this* file
      _defaults:
          autowire: true      # Automatically injects dependencies in your services.
          autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
          public: false       # Allows optimizing the container by removing unused services; this also means
                              # fetching services directly from the container via $container-&gt;get() won't work.
                              # The best practice is to be explicit about your dependencies anyway.
          bind:
              App\Service\MessageSenderServiceInterface: '@App\Service\MessageSenderRedisService'
  </code></pre>
  
  <h1>Controller.php</h1>
  
  <pre><code>use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  
  class TestController extends AbstractController
  {
      /**
       * @Route("/api/dummy")
       */
      public function dummyEndpoint(MessageSenderServiceInterface $messageSender)
      {
          echo get_class($messageSender); exit;
      }
  }
  </code></pre>
  
  <p>And the echo from controller for both envs (prod and dev) is</p>
  
  <pre><code>App\Service\MessageSenderSqsService
  </code></pre>
  
  <p>But if I copy whole node "services" form services.yaml to services_dev.yaml and only change the binding config, it works fine and says that the injected class is:</p>
  
  <pre><code>App\Service\MessageSenderRedisService
  </code></pre>
  
  <hr>
  
  <p>I've just noticed that if I don't touch the "_defaults" node, it works as expected, the problems start only when I want to override the _defaults node of services...</p>