I'm currently writing a REST-tool that connects to a third-party server (duh). They offer a fairly large (if not too large) API in a single wsdl file, as well as separate wsdl's for each specific part of data you want to work on.
When writing my code, I created an abstract Api
class, and a number of child classes, one for each subset of the API.
Since all requests are available through a single, "master-api", there is only 1 user-password required to connect, so I've created the getClient
and setClient
methods in the abstract class.
Since it's not unlikely form me to be working with two, or three of these API-classes, I decided to create a private static property in the abstract class. This is to avoid excessive internal method calls, brought along by lazy-loading.
Is this a valid use-case for the static
keyword? It's the only time I'm using static
in my entire code, and I have this acquired repulsion for using it.
Anyway, here's some (grossly oversimplified) version of my code:
namespace MyLib;
use Tool\Application,
Tool\Command;//it's a CLI tool
use MyLib\Soap\Client;
use \Zend_Config;//can't help but liking the old Zend_Config
absctract class Api
{
//all properties have a getter, which lazy-loads the correct object, where possible
//can be injected through constructor, setter or via $this->command
private $app = null;
//inject via setter, get from application or command
private $config = null;
//inject via setter or child constructor
private $command = null;
/* This is the one */
private static $login;
public function __construct(Application $app = null)
{
$this->setApplication($app);
if (!is_callable(array($this, 'init')))
{
throw new \RuntimeException('Impossible, yet somehow '.get_class($this).'::init() cannot be called');
}
return $this->init();
}
abstract protected functoin init();
final private function getLogin()
{
if (self::$login === null)
{
$config = $this->getConfig();
$this->setLogin(array(
array(
'login' => $config->api->login,
'pwd' => $config->api->pwd
)
);
}
return self::$login;
}
final private function setLogin(array $login)
{
if (count(array_filter($login) === 2)
{
self::$login = $login;
}
return $this;
}
protected fucntion getClient()
{
if ($this->client === null)
{
$wsdl = $this->getConfig();
$wsdl->api->{$this->getName()}->wsdl;
$this->setClient(
new Client(
$wsdl,
$this->getLogin()
)
);
}
return $this->client;
}
public fucntion setClient(Client $client = null)
{
if ($this->client)
{
$this->client->disconnect();
}
$this->client = $client;
return $this;
}
protected function getConfig()
{
if ($this->config === null)
{//getApplication falls back to $this->getCommand()->getApplication()
$this->setConfig(
$this->getApplication()->getConfig()
);
}
return $this->config;
}
public function setConfig(Zend_Config $config = null)
{
$this->config = $config;
return $this;
}
}
As for the child classes, they look something like this:
namespace MyLib\Apis;
use MyLib\Api;
use MyLib\Data\Models\Model;
class Foo extends Api
{
public function __construct($mixed = null)
{
if ($mixed instanceof Command)
{
$this->setCommand($mixed);
}
parent::__construct($mixed instanceof Application ? $mixed : null);
}
protected function init()
{
$this->setName('foo');//<-- init is a tad more complicated, but not relevant here
}
public function doRequest(Model $data = null)
{
$client = $this->getClient();
//worst case here:
// parent::getClient getConfig -> getApplication -> getCommand {->setApplication(command->getApplication())}->getConfig <== setConfig of $this here
return $client->getSomething(
array(
'param' => $data->foobar
)
);
}
}
Every getClient
can result in as much as 12 method calls. By creating a static array containing the login data, I can make sure that the maximum number of calls is 12 once, and then, a maximum of 9 calls applies to all instances.
If this is indeed a good use case for statics, I'm thinking of creating a second static (though my heart really is bleeding just thinking about it) that'll hold the Application
instance, which, in order for an application to use my lib, it needs to hold the config file, which is what I'm after.
If I create those two statics, the theoretical maximum of 12 method calls remains, but after the full 12 calls have been made once, This can be reduced to only 4 when I'm getting the config, 6 upon calling getClient
the first time.
Half of the calls I'm currently making, which, could make a difference IMO