parent
c0328df9e6
commit
f56b209d5c
7 changed files with 130 additions and 3 deletions
@ -1,7 +1,8 @@ |
||||
# EXT/LIB integration tests |
||||
|
||||
This suite protects build-mode boundaries rather than duplicating the PHP |
||||
syntax coverage in `tests/compiler`. |
||||
This suite lives below `.github` because repository test fixtures with a `.php` |
||||
suffix are intentionally ignored below `tests/`. It protects build-mode |
||||
boundaries rather than duplicating the PHP syntax coverage in `tests/compiler`. |
||||
|
||||
- `ext/lifecycle` builds a real Zend extension and loads it through CLI, |
||||
`php -S`, and PHP-FPM. The long-running hosts alternate implementations of |
||||
@ -0,0 +1,57 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
$request = PHP_SAPI === 'cli' |
||||
? (int) getenv('TYPEPHP_INTEGRATION_REQUEST') |
||||
: (int) ($_GET['request'] ?? 0); |
||||
|
||||
// Alternate the implementation attached to the same request-local symbols. |
||||
// A stale pointer surviving RSHUTDOWN will either call the preceding request's |
||||
// implementation, access released memory, or crash the long-running host. |
||||
if ($request % 2 === 0) { |
||||
final class TypePhpIntegrationRequestValue |
||||
{ |
||||
public function __construct(private int $value) |
||||
{ |
||||
} |
||||
|
||||
public function render(): string |
||||
{ |
||||
return 'even:' . $this->value; |
||||
} |
||||
} |
||||
|
||||
function typephp_integration_request_transform(string $value): string |
||||
{ |
||||
return 'even-handler[' . $value . ']'; |
||||
} |
||||
} else { |
||||
final class TypePhpIntegrationRequestValue |
||||
{ |
||||
public function __construct(private int $value) |
||||
{ |
||||
} |
||||
|
||||
public function render(): string |
||||
{ |
||||
return 'odd:' . $this->value; |
||||
} |
||||
} |
||||
|
||||
function typephp_integration_request_transform(string $value): string |
||||
{ |
||||
return 'odd-handler[' . $value . ']'; |
||||
} |
||||
} |
||||
|
||||
header('Content-Type: application/json'); |
||||
echo json_encode([ |
||||
'request' => $request, |
||||
'results' => [ |
||||
typephp_integration_probe($request), |
||||
typephp_integration_probe($request), |
||||
], |
||||
'main_registered' => function_exists('main'), |
||||
'pid' => getmypid(), |
||||
], JSON_THROW_ON_ERROR); |
||||
@ -0,0 +1,24 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
function typephp_integration_probe(int $request): string |
||||
{ |
||||
static $calls = 0; |
||||
++$calls; |
||||
|
||||
// DateTimeImmutable and its format() method are internal, module-lifetime |
||||
// symbols. The host class/function below are rebuilt for every request and |
||||
// therefore exercise the request-lifetime class/function cache domain. |
||||
$date = new DateTimeImmutable('@' . $request); |
||||
$value = new TypePhpIntegrationRequestValue($request); |
||||
return $calls . '@' . $date->format('U') . '|' |
||||
. typephp_integration_request_transform($value->render()); |
||||
} |
||||
|
||||
// main() belongs to the embedded bin entry path. An extension must neither |
||||
// register it as a PHP function nor invoke it from RINIT. |
||||
function main(): void |
||||
{ |
||||
throw new RuntimeException('ext mode invoked bin main()'); |
||||
} |
||||
@ -0,0 +1,16 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
use TypePhpIntegration\Library\Counter; |
||||
use function TypePhpIntegration\Library\add; |
||||
|
||||
function main(): void |
||||
{ |
||||
echo add(19, 23), "\n"; |
||||
|
||||
$counter = new Counter(); |
||||
$counter->add(3); |
||||
$counter->add(4); |
||||
echo 'counter=', $counter->value, "\n"; |
||||
} |
||||
@ -0,0 +1,29 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace { |
||||
// lib mode owns an embedded module but must not execute the bin entrypoint. |
||||
// This declaration must also be omitted from the published import stub. |
||||
function main(): void |
||||
{ |
||||
throw new RuntimeException('lib mode invoked bin main()'); |
||||
} |
||||
} |
||||
|
||||
namespace TypePhpIntegration\Library { |
||||
function add(int $left, int $right): int |
||||
{ |
||||
return $left + $right; |
||||
} |
||||
|
||||
final class Counter |
||||
{ |
||||
public int $value = 0; |
||||
|
||||
public function add(int $delta): int |
||||
{ |
||||
return $this->value += $delta; |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue