1

I have some PHP code that connects to shopping cart API (SOAP) endpoints. This is not to one central server, but rather to any number of user's specific endpoint URLs.

Right now I have several different classes that all create their own connection to the users API.

E.G.,

CartProduct.php -> updateProduct() (creates api connection)

CartCategory.php -> updateCategory() (creates api connection)

I was thinking of using a Singleton to share the remote connection, but after reading through questions on SO, and some blogs, apparently everyone hates Singleton.

In my case I don't think a connection pool makes sense. I'm connecting to a remote user's website, so I don't just want to open 5 connections and potentially slow down their website. I think in this case I really want to share ONE connection between this call to the application. I think in the case of a DB, a connection pool makes sense, but not for remote user APIs. Now theoretically, I guess we should think about what happens if the user tries to run updateProduct and updateCategory at the same time... will that break the system?

Is there a design pattern that makes sense here to open a connection which several different classes can share??

Jimbo
  • 24,043
  • 14
  • 77
  • 118
bonez
  • 675
  • 1
  • 16
  • 38
  • Singleton is useful when you "need" it and it's up to you to choose when to use it. Otherwise, why not create an api connection and pass it through to the appropriate class instance for product or category respectively. It doesn't have to be a singleton to simply use the same database object on each other instance. I'm not 100% on the using the same connection though for multiple requests if one isn't finished though. – Moylin Aug 01 '13 at 16:15
  • @Moylin , singleton is useful, if you know only how to write procedural code, but the project leader demanded that you use classes and all that other strange object-stuff. – tereško Aug 01 '13 at 16:17
  • @tereško - patterns are a solution. Sometimes you don't have the problem. They can be good and effective for small works. But I understand the viewpoint. Only singleton I've used myself is for DB when i get lazy on my own projects. But since using a DI, it doesn't have to be a singleton, but you just call the same instance of the class unless you need a new one. – Moylin Aug 01 '13 at 16:24
  • 1
    @Moylin , you might look into [this](http://stackoverflow.com/a/11369679/727208) fragment. This is the "problem" that is solved by singletons: *"How can I have global state using classes?"*. – tereško Aug 01 '13 at 16:28
  • Which I would have known about this library. Would have been exactly what I needed: https://github.com/guzzle/guzzle – bonez Aug 14 '13 at 19:49

1 Answers1

6

I have no idea if this pattern has a name

In my humble opinion, the connection pool would actually make sense. Only you should not initialize all the connections right off. Instead use lazy initialization:

class LazyPool
{

    private $connections = [];
    private $providers = [];

    public function addProvider($name, callable $provider)
    {
        $this->providers[$name] = $provider;
        return $this;
    }

    public function getConnection($name)
    {
        if (array_key_exists($name, $this->connections) === false)
        {
            $this->connections[$name] = call_user_func($this->providers[$name]);
        }
        return $this->connections[$name];
    }

}

This class can would be used like this:

$pool = new LazyPool;

$pool->addProvider('lorem', function() use ($config){
    $instance = new SoapThing($config['wsdl_1']);
    return $instance;
});

$pool->addProvider('ipsum', function() use ($config){
    $instance = new SoapThing($config['i_think_it_was_wsdl']);
    return $instance;
});

$foo = new Foo($pool);
$bar = new Bar($pool);

This way both instance will be able to initialize SOAP connection, but if Foo initialized connection named "ipsum", then Bar instance will get from pool the already initialized SOAP client.

Disclaimer:
This code was not tested. It was written directly in the SO post editor using some copy-paste from older post of mine. This particular syntax also will require PHP 5.4+, therefore you might need to adapt it for running in older PHP 5.* versions.

tereško
  • 56,151
  • 24
  • 92
  • 147