Re: [RFC] Default expression

From: Date: Mon, 26 Aug 2024 12:28:35 +0000
Subject: Re: [RFC] Default expression
References: 1 2 3  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
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]


Thread (101 messages)

« previous php.internals (#125269) next »