SlideShare a Scribd company logo
1 of 68
Download to read offline
Simplifiez-vous les Design
  Patterns avec PHP 5.3
        Hugo Hamon – 12/07/12
Observateur

Dependency Injection

Inversion de Contrôle
Observer
Un sujet, l’objet
observable, émet un signal
à des modules qui jouent
le rôle d’observateurs.
Event Dispatcher
Le Dispatcheur est un objet
qui gère les connexions
entre le sujet observé et ses
observateurs (écouteurs).
# composer.json

{
    "require": {
        "php": ">=5.3.3",
        "symfony/event-dispatcher": "2.1.*"
    }
}
use SymfonyComponentEventDispatcherEvent;
use SymfonyComponentEventDispatcherEventDispatcher;
use AFUPArticleListener;

$dispatcher = new EventDispatcher();

// Déclaration des écouteurs
$listener1 = array(new ArticleListener(), 'onDelete');
$listener2 = array(new ArticleListener(), 'onSave');

// Enregistrement des écouteurs
$dispatcher->addListener('article.delete', $listener1);
$dispatcher->addListener('article.pre_save', $listener2);

// Notification des écouteurs
$dispatcher->dispatch('article.pre_save', new Event());
Mise en Pratique
use AFUPModelArticle;

$article = new Article();
$article->setTitle('AFUP Design Patterns');
$article->setContent('Some **content**');
$article->save();

echo $article->getHtmlContent();
<p>
      Some <strong>content</strong>
</p>
namespace AFUPModel;

use PropelRuntimeConnectionConnectionInterface;
use dflydevmarkdownMarkdownParser;

class Article extends AFUPModelBaseArticle
{
    public function save(ConnectionInterface $con = null)
    {
        $parser = new MarkdownParser();
        $html = $parser->transformMarkdown($this->getContent());
        $this->setHtmlContent($html);

        $ret = parent::save($con);

        $this->updateLuceneIndex();

        return $ret;
    }
}
Le Sujet
   Observé
namespace AFUPModel;

use SymfonyComponentEventDispatcherEventDispatcher;
use AFUPModelBaseArticle as BaseArticle;

class Article extends BaseArticle
{
    private $dispatcher;

    public function setDispatcher(EventDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }
}
namespace AFUPModel;

// ...
use PropelRuntimeConnectionConnectionInterface;
use AFUPEventArticleEvent;

class Article extends BaseArticle
{
    // ...
    public function save(ConnectionInterface $con = null)
    {
        $event = new ArticleEvent($this);
        $this->dispatcher->dispatch('article.pre_save', $event);

         $ret = parent::save($con);
         $this->dispatcher->dispatch('article.post_save', $event);

         return $ret;
    }
}
Propager un
   Evénement
namespace AFUPEvent;

use SymfonyComponentEventDispatcherEvent;
use AFUPModelArticle;

class ArticleEvent extends Event
{
    private $article;

    public function __construct(Article $article)
    {
        $this->article = $article;
    }

    public function getArticle()
    {
        return $this->article;
    }
}
Ajouter des
   écouteurs
namespace AFUPListener;

use AFUPEventArticleEvent;
use dflydevmarkdownMarkdownParser;

class ArticleListener
{
    public function onPreSave(ArticleEvent $event)
    {
        $article = $event->getArticle();
        $markdown = $article->getContent();

        $parser = new MarkdownParser();
        $html = $parser->transformMarkdown($markdown);
        $article->setHtmlContent($html);
    }
}
namespace AFUPListener;

use   ZendSearchLuceneDocument;
use   ZendSearchLuceneDocumentField;
use   AFUPEventArticleEvent;
use   AFUPModelArticlePeer;

class LuceneListener
{
    public function onPostSave(ArticleEvent $event)
    {
        $article = $event->getArticle();

          // ...
      }
}
namespace AFUPListener;

// ...
class LuceneListener
{
    public function onPostSave(ArticleEvent $event)
    {
        $article = $event->getArticle();
        $index = ArticlePeer::getLuceneIndex();

        // remove existing entries
        foreach ($index->find('pk:'.$article->getId()) as $hit) {
            $index->delete($hit->id);
        }

        $doc = new Document();
        $doc->addField(Field::Keyword('pk', $article->getId()));
        $doc->addField(Field::UnStored('title', $article->getTitle()));
        $doc->addField(Field::UnStored('content', $article->getContent()));

        $index->addDocument($doc);
        $index->commit();
    }
}
Enregistrer les
    écouteurs
use   SymfonyComponentEventDispatcherEventDispatcher;
use   AFUPListenerArticleListener;
use   AFUPListenerLuceneListener;
use   AFUPModelArticle;

// Déclaration des écouteurs
$listener1 = array(new ArticleListener(), 'onPreSave');
$listener2 = array(new LuceneListener(), 'onPostSave');

// Enregistrement des écouteurs
$dispatcher = new EventDispatcher();
$dispatcher->addListener('article.pre_save', $listener1);
$dispatcher->addListener('article.post_save', $listener2);
$article = new Article();

$article->setDispatcher($dispatcher);

$article->setTitle('AFUP Design Patterns');

$article->setMarkdownContent(
    'Some **markdown** content'
);

$article->save();
Dependency Injection
Mauvaise
Conception
Initiale
class Mailer
{
    public function send(Message $message)
    {
        try {
             $transport = new SMTPTransport(
                 'smtp.foo.com', 1234, 'mailer', 'p$wD^'
             );
             return $transport->send($message);
        } catch (TransportException $e) {
             $logger = Logger::getInstance();
             $logger->log('Unable to send message to...');
             $logger->logException($e);
             throw $e;
        }
    }
}
$message = new Message();
$message->setFrom('me@example.com');
$message->setTo('you@example.com');
$message->setSubject('Bonjour ...');
$message->setBody('Hello ...');

$mailer = new Mailer();
$mailer->send($message);
Ca fonctionne !
Oui mais ?!!!
$transport = new SMTPTransport(
    'smtp.foo.com',
     1234,
     'mailer',
     'p$wD^'
);
Je veux utiliser
un transport
différent…
Je veux configurer
le SMTP en dev et
en prod…
$logger = Logger::getInstance();
$logger->log('Unable to...');
$logger->logException($e);
Si le logger
n’existe pas ?
Si je veux changer
la configuration
du logger?
Je veux tester mon
code avec PHPUnit
et je n’y arrive
pas…
La Solution?
Injecter ses
dépendances au
Mailer
What ???
Injection par
les propriétés
class Mailer
{
    public $transport;

    public function send(Message $message)
    {
        try {
            $this->transport->send($message);
        } catch (TransportException $e) {
            // ...
        }
    }
}
$message = Message();
$message->setFrom('me@example.com');
$message->setTo('you@example.com');
$message->setSubject('Bonjour ...');
$message->setBody('Hello ...');

$transport = new SMTPTransport('...');

$mailer = new Mailer();
$mailer->transport = $transport;
$mailer->send($message);
Injection par
constructeur
class Mailer
{
    private $transport;

    function __construct(Transport $t)
    {
        $this->transport = $t;
    }
}
$message = Message();
$message->setFrom('me@example.com');
// ...

$transport = new SMTPTransport('...');

$mailer = new Mailer($transport);
$mailer->send($message);
Injection par
un mutateur
class Mailer
{
    private $logger;

    function setLogger(Logger $logger)
    {
        $this->logger = $logger;
    }
}
class Mailer
{
    // ...
    public function send(Message $message)
    {
        try {
             $this->transport->send($message);
        } catch (TransportException $e) {
             if (null !== $this->logger) {
                 $this->logger->log('...');
                 $this->logger->logException($e);
                 throw $e;
             }
        }
    }
}
$message = Message();
// ...

$logger = new FileLogger('/to/dev.log');
$transport = new SMTPTransport('...');

$mailer = new Mailer($transport);
$mailer->setLogger($logger);
$mailer->send($message);
Découplage
avec les
interfaces
class Mailer
{
    function __construct(TransportInterface $t)
    {
        $this->transport = $t;
    }

    function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}
class SMTPTransport implements TransportInterface
{
}

class MailTransport implements TransportInterface
{
}

class NullTransport implements TransportInterface
{
}
Bénéfices vs
Pertes ?!
Configurabilité
   Modularité
      Testabilité
Construction
   un peu plus
      Complexe
Inversion de Contrôle
# composer.json
{
    "require": {
        "pimple/pimple": "1.0.*"
    }
}
Global Configuration
    + Lazy Services
        = Container
Paramètres
Globaux de
Configuration
$pimple = new Pimple();

$pimple['logger.file'] = '/path/to/dev.log';
$pimple['logger.severity'] = 200;

$pimple['transport.smtp.host'] =   'smtp.foo.com';
$pimple['transport.smtp.port'] =   1234;
$pimple['transport.smtp.user'] =   'mailer';
$pimple['transport.smtp.passwd']   = '^p4$$W0rD*';
Enregistrer
des services
$pimple['logger'] = $pimple->share(function ($c) {

      if (!is_writable($c['logger.file'])) {
          throw new Exception('...');
      }

      $logger = new Logger($c['logger.file']);

      if (isset($c['logger.severity'])) {
          $logger->setSeverity($c['logger.severity']);
      }

      return $logger;
});
$pimple['mailer.transport'] = $pimple
->share(function ($c) {

      return new SMTPTransport(
          $c['transport.smtp.host'],
          $c['transport.smtp.port'],
          $c['transport.smtp.user'],
          $c['transport.smtp.passwd']
      );
});
$pimple['mailer'] = $pimple->share(function ($c) {

      $mailer = new Mailer($c['mailer.transport']);

      if (isset($c['logger'])) {
          $mailer->setLogger($c['logger']);
      }

      return $mailer;
});
Initialisation des
services à la
demande
$pimple = new Pimple();
$pimple['logger.file'] = '/path/to/dev.log';
$pimple['logger.severity'] = 200;
// ...

$message = Message();
$message->setFrom('me@example.com');
// ...

// Création à la demande du mailer
$pimple['mailer']->send($message);
Design Patterns avec PHP 5.3, Symfony et Pimple

More Related Content

What's hot

Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
Bill Chang
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
Fabien Potencier
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
Hugo Hamon
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
Fabien Potencier
 

What's hot (20)

Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of Lithium
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 
Symfony War Stories
Symfony War StoriesSymfony War Stories
Symfony War Stories
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 

Similar to Design Patterns avec PHP 5.3, Symfony et Pimple

SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
jsmith92
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
smueller_sandsmedia
 

Similar to Design Patterns avec PHP 5.3, Symfony et Pimple (20)

How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Extbase and Beyond
Extbase and BeyondExtbase and Beyond
Extbase and Beyond
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for PerformanceMeet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
 
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Oops in php
Oops in phpOops in php
Oops in php
 
The IoC Hydra
The IoC HydraThe IoC Hydra
The IoC Hydra
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 

More from Hugo Hamon

Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec Jenkins
Hugo Hamon
 
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkExposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Hugo Hamon
 

More from Hugo Hamon (11)

Monitor the quality of your Symfony projects
Monitor the quality of your Symfony projectsMonitor the quality of your Symfony projects
Monitor the quality of your Symfony projects
 
Intégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIIntégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CI
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console component
 
Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec Jenkins
 
Symfony2 en pièces détachées
Symfony2 en pièces détachéesSymfony2 en pièces détachées
Symfony2 en pièces détachées
 
Mieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyMieux Développer en PHP avec Symfony
Mieux Développer en PHP avec Symfony
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2
 
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkExposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
 

Recently uploaded

Recently uploaded (20)

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 

Design Patterns avec PHP 5.3, Symfony et Pimple