🎁 Perplexity PRO offert
Optimize Your PrestaShop Modules with Symfony Service Lazy Loading
Introduction
Since PrestaShop relies on Symfony (from version 1.7.6 and reinforced in PrestaShop 8 and 9), we have access to the full power of the service container. Yet, many module developers continue to load their services “eagerly”… even when they’re almost never used.
The result? More slowness, more memory consumed for nothing. The solution: enable lazy loading of services. In this article, we’ll see how this simple technique can transform your PrestaShop module performance.
Understanding Service Lazy Loading
What is Lazy Loading?
The principle is simple:
- Without lazy loading → Symfony instantiates your service immediately at startup
- With lazy loading → Symfony places a proxy. The actual service is only created on first call
To understand well, let’s imagine a metaphor: your service is like a delivery truck 🚚.
- Without lazy: the truck starts at every request, even if it’s empty
- With lazy: it only starts when you actually have a package to deliver
Concrete Benefits
This approach brings several advantages:
- Reduced memory consumption: only used services are instantiated
- Faster response times: fewer objects to create at startup
- Better scalability: your module adapts better to load
Why This is Particularly Useful in PrestaShop
PrestaShop modules often contain heavy services:
- API clients (Stripe, Amazon S3, ChatGPT, etc.)
- Excel/CSV parsers for import/export
- PDF generators for invoices
- Redis or Elasticsearch cache clients
The problem? Most pages in your store don’t need these services. Without lazy loading, you waste precious resources. With lazy loading, these services only load when actually necessary.
Practical Implementation in a Module
Example of a Heavy External Service
Let’s start by creating a service that simulates an external API client:
// src/Infra/External/ApiClient.php
namespace MyVendor\MyModule\Infra\External;
final class ApiClient
{
public function __construct(private string $apiKey)
{
// Simulation of expensive initialization
// (network connection, authentication, etc.)
}
public function fetchCatalog(): array
{
// External API call to retrieve a catalog
// Potentially slow operation
return [
['id' => 1, 'name' => 'Product 1'],
['id' => 2, 'name' => 'Product 2'],
];
}
}
Service Configuration with Lazy Loading
Here’s how to configure this service in your services.yml file:
# modules/mymodule/config/services.yml
services:
_defaults:
autowire: true
autoconfigure: true
public: false
MyVendor\MyModule\Infra\External\ApiClient:
arguments:
$apiKey: '%env(MYMODULE_API_KEY)%'
lazy: true # 💡 Proxy is generated only when needed
Application Service Using the API Client
Let’s now create a service that uses our API client:
// src/App/Catalog/SyncCatalog.php
namespace MyVendor\MyModule\App\Catalog;
use MyVendor\MyModule\Infra\External\ApiClient;
class SyncCatalog
{
public function __construct(private ApiClient $client) {}
public function __invoke(): int
{
$rows = $this->client->fetchCatalog();
// Synchronization logic with PrestaShop
// (product creation/update)
return \count($rows);
}
}
Symfony Controller to Trigger Synchronization
Finally, a controller that uses our service:
// src/Ui/Controller/Admin/CatalogController.php
namespace MyVendor\MyModule\Ui\Controller\Admin;
use MyVendor\MyModule\App\Catalog\SyncCatalog;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
final class CatalogController extends AbstractController
{
public function sync(SyncCatalog $useCase): Response
{
// Only here will ApiClient be actually instantiated
$count = $useCase();
$this->addFlash('success', "$count products synchronized!");
return $this->redirectToRoute('mymodule_catalog_index');
}
}
Best Practices and Use Cases
When to Enable Lazy Loading
Lazy loading is particularly beneficial for:
- External API clients: Stripe, PayPal, delivery services
- Heavy processing services: Excel manipulation, PDF generation, image processing
- Export/import features: rarely used but expensive
- Cache clients: Redis, Memcached when not always necessary
When to Avoid Lazy Loading
Conversely, avoid lazy loading for:
- Simple helpers: lightweight services used everywhere
- Critical services: used in every request
- Logging services: must be immediately available
Pitfalls to Avoid and Best Practices
Beware of Final Classes
If your service is a final class, Symfony cannot create a proxy. Prefer an interface:
interface ApiClientInterface
{
public function fetchCatalog(): array;
}
final class ApiClient implements ApiClientInterface
{
// Implementation...
}
# Configuration with interface
services:
MyVendor\MyModule\Infra\External\ApiClientInterface:
class: MyVendor\MyModule\Infra\External\ApiClient
arguments:
$apiKey: '%env(MYMODULE_API_KEY)%'
lazy: true
Avoid Serializing Proxies
Lazy proxies should not be serialized. If you need to persist a service’s state, extract the necessary data first.
Test Performance
Use tools like Blackfire or the Symfony profiler to measure real impact:
# Debug services and their proxies
bin/console debug:container --show-private
Advanced Technique: Service Subscriber
For even finer control, use the ServiceSubscriberInterface pattern:
use Symfony\Contracts\Service\ServiceSubscriberInterface;
use Psr\Container\ContainerInterface;
final class MyController extends AbstractController implements ServiceSubscriberInterface
{
public static function getSubscribedServices(): array
{
return [
'syncCatalog' => SyncCatalog::class,
'apiClient' => ApiClientInterface::class,
];
}
public function __construct(private ContainerInterface $locator) {}
public function sync(): Response
{
// Service is only retrieved when needed
$useCase = $this->locator->get('syncCatalog');
$count = $useCase();
$this->addFlash('success', "$count products synchronized!");
return $this->redirectToRoute('mymodule_catalog_index');
}
}
Measuring Performance Impact
To evaluate lazy loading effectiveness in your context, here are some metrics to monitor:
Memory Consumed
// Before and after lazy loading activation
echo "Memory used: " . memory_get_peak_usage(true) / 1024 / 1024 . " MB\n";
Page Loading Times
Use the Symfony profiler or external tools to measure response time for pages that don’t use your heavy services.
Conclusion
Service lazy loading is a small configuration tweak that can have a considerable impact on your PrestaShop module performance:
- Significant reduction in memory consumption
- Faster response times for unaffected pages
- More scalable and professional modules
Next time you develop a module with heavy services, think about adding that simple lazy: true line in your configuration. Your users and your server will thank you!
Don’t hesitate to test this technique on your existing projects and share your results with the PrestaShop community.
Article published on October 2, 2025 by Nicolas Dabène - PHP & PrestaShop Expert with 15+ years of experience
Questions Fréquentes
What is Symfony service lazy loading?
Lazy loading is a technique where Symfony places a proxy instead of immediately instantiating your service at startup. The actual service is only created on first actual call. It’s like a delivery truck that only starts when you actually have a package to deliver.
Why is lazy loading important for PrestaShop modules?
PrestaShop modules often contain heavy services (API clients, Excel/CSV parsers, PDF generators, Redis clients) that most pages don’t use. Without lazy loading, you waste memory and startup time. With lazy loading, these services only load when actually needed.
How to enable lazy loading in a PrestaShop service?
In your config/services.yml file, simply add lazy: true in your service configuration. For example: MyVendor\MyModule\Infra\External\ApiClient: arguments: $apiKey: ‘%env(MYMODULE_API_KEY)%’ lazy: true. The proxy will be automatically generated by Symfony only when needed.
When should you avoid lazy loading?
Avoid lazy loading for simple helpers and lightweight services used everywhere, critical services used in every request, and logging services that must be immediately available. Lazy loading is beneficial only for heavy services used occasionally.
How to solve the final class problem with lazy loading?
If your service is a final class, Symfony cannot create a proxy. Prefer an interface: create an ApiClientInterface, make your final class implement it, then configure the service with the interface as class. Lazy loading will then work on the interface.
Articles Liés
Automatiser vos Publications Facebook et Instagram avec n8n : Le Guide Salvateur
Si vous pensiez que l'intégration Meta serait un jeu d'enfant, ce guide détaillé va vous éviter des heures de frustra...
Préparer votre boutique PrestaShop pour le Black Friday 2025 avec le module Advanced Search Pro
Découvrez comment le module Advanced Search Pro peut transformer votre boutique PrestaShop en machine à ventes pour l...
Le Guide Définitif pour Mesurer le GEO : Du Classement SEO à l'Influence IA
L'émergence des moteurs génératifs a catalysé une transformation fondamentale du marketing numérique. Découvrez le ca...
Google Shopping & Black Friday 2025 : Guide Complet pour PrestaShop
Découvrez comment optimiser votre présence Google Shopping pour le Black Friday 2025 en Europe et maximiser vos reven...
Comprendre le Model Context Protocol (MCP) : Une Conversation Simple
Découvrez comment les IA peuvent accéder à vos fichiers et données grâce au MCP, expliqué à travers une conversation ...
🧩 Énigme PrestaShop : Saurez-vous trouver les 5 erreurs ?
Développeurs PrestaShop, je vous lance un défi ! Découvrez les 5 erreurs courantes dans ce module de best-sellers et ...
Découvrez mes autres articles
Guides e-commerce, tutoriels PrestaShop et bonnes pratiques pour développeurs
Voir tous les articles