On Mon, 26 Aug 2024, at 11:43, Mike Schinkel wrote:
>> You ask how a library can provide access to that default, and the answer is generally
>> pretty trivial: define a public constant, and refer to it in the parameter definition.
>
> A global? Really?
I didn't say "global", I said "public". Since you're keen on
real-world examples, here's a simplified version of a real class:
class ConfigSource
{
private HttpClientInterface $httpClient;
public const DEFAULT_CONSUL_URL = 'http://localhost:8500';
public function __construct(private string $consulUrl=self::DEFAULT_CONSUL_URL,
?HttpClientInterface $httpClient=null)
{
if ( $httpClient === null ) {
$httpClient = new HttpClient();
$httpClient->setRequestTimeoutSecs(5);
$httpClient->setConnectRequestTimeoutSecs(5);
}
$this->httpClient = $httpClient;
}
}
This constructor has two optional parameters; one of them uses a default which is also referenced
explicitly in another class, so is exposed as a constant; the other uses a completely opaque method
of creating a default object, which even Reflection could not expose.
The caller doesn't need to know how any of this works to make use of the class. The contract is
"__construct(optional string $consulUrl, optional ?HttpClientInterface $httpClient)"
The purpose of the optional parameters is so that you can write "$configSource = new
ConfigSource();" and trust the library to provide you a sensible default behaviour.
If it was decided that the code for creating a default HttpClient was needed elsewhere, it could be
refactored into a method, with appropriate access:
public function __construct(private string $consulUrl=self::DEFAULT_CONSUL_URL, ?HttpClientInterface
$httpClient=null)
{
$this->httpClient = $httpClient ?? $this->getDefaultHttpClient();
}
public function getDefaultHttpClient(): HttpClient
{
$httpClient = new HttpClient();
$httpClient->setRequestTimeoutSecs(5);
$httpClient->setConnectRequestTimeoutSecs(5);
return $httpClient;
}
Or perhaps the HttpClient becomes nullable internally:
public function __construct(private string $consulUrl=self::DEFAULT_CONSUL_URL, private
?HttpClientInterface $httpClient=null) {}
Or maybe we allow explicit nulls, but default to a simple class instantiation:
public function __construct(private string $consulUrl=self::DEFAULT_CONSUL_URL, private
?HttpClientInterface $httpClient=new HttpClient) {}
None of these are, currently, breaking changes - the contract remains "__construct(optional
string $consulUrl, optional ?HttpClientInterface $httpClient)".
Regards,
---
Rowan Tommins
[IMSoP]