Created
August 28, 2024 21:29
-
-
Save IMSoP/16e2422d86e3ab513d6b0658009d0c06 to your computer and use it in GitHub Desktop.
Default parameter type variance examples for https://wiki.php.net/rfc/default_expression
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Acme\Log { | |
interface Logger { | |
public function log(string $message, int $level=5); | |
} | |
function use_acme_logger(Logger $logger) { | |
$logger->log('Hello', default - 1); | |
} | |
} | |
namespace OmniCorp\Log { | |
interface Logger { | |
public function log(string $message, string $level='ERROR'); | |
} | |
function use_omnicorp_logger(Logger $logger) { | |
$logger->log('Hello', default . '!'); | |
} | |
} | |
namespace MyCoolApp { | |
class MyCoolLogger implements \Acme\Log\Logger, \OmniCorp\Log\Logger { | |
// Since we can widen the input type, we can supply the same class to libraries using both interfaces | |
// It doesn't actually matter which type we pick for the default, but we can't keep both | |
// So either use_acme_logger or use_omnicorp_logger is going to break, even though we met the interface | |
public function log(string $message, int|string $level='ERROR') { | |
if ( is_int($level) ) { | |
$level = match($level) { | |
5 => 'ERROR', | |
4 => 'WARNING', | |
// ... | |
}; | |
} | |
echo "$level: $message\n"; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Version 1.0 | |
class Foo { | |
public function __construct(int $timeout=60) { | |
// ... | |
} | |
} | |
// Version 1.1 | |
class Foo { | |
public function __construct(?int $timeout=null) { | |
if ( $timeout !== null ) { | |
trigger_error( | |
'Setting a global timeout is deprecated, use the configureTimeouts() method instead.', | |
E_USER_DEPRECATED | |
); | |
} | |
// ... | |
} | |
} | |
// Looks reasonable in version 1.0, passes a default of 0 after upgrading to version 1.1 | |
$foo = new Foo(default * 2); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
interface FooInterface { | |
public const FLAG_PRETTY = 0b0001; | |
public const FLAG_FAST = 0b0010; | |
public function bar(int $flags = self::FLAG_PRETTY); | |
} | |
function use_a_foo(FooInterface $foo) { | |
// Seems safe, interface says it's an optional int, so I can do bitwise ops on the default | |
$foo->bar(default | ForInterface::FLAG_FAST); | |
} | |
use_a_foo(new BetterFoo); // TypeError! Cannot use bitwise or on object of type FooOptions | |
class FooOptions { | |
public bool $pretty=true; | |
public const SPEED_SLOW=1; | |
public const SPEED_FAST=2; | |
public const SPEED_CRAZY=3; | |
public int $speed = self::SPEED_SLOW; | |
public static function fromBitFlags(int $flags): self { | |
// ... | |
} | |
} | |
class BetterFoo implements FooInterface { | |
public function bar(int|FooOptions $flags = new FooOptions) { | |
if ( is_int($flags) ) { | |
$flags = FooOptions::fromBitFlags($flags); | |
} | |
// carry on using FooOptions | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Version 1.0 | |
class ApiClient { | |
public function __construct(private HttpClient $httpClient = new HttpClient) {} | |
} | |
// User code | |
$client = new ApiClient( default->withUserAgent('AwesomeApp/666') ); | |
// Version 1.1 | |
class ApiClient { | |
public function __construct(private NetworkClient $httpClient = new WebSocketClient) {} | |
} | |
// User code now breaks because WebSocketClient doesn't have a withUserAgent() method |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment