refactor(php): 将 stream_cast 函数替换为 toStream 方法

- 移除 stream_cast 全局函数实现
- 将 stream_cast($stream) 调用转换为 $stream->toStream() 方法调用
- 更新编译器中的流类型识别逻辑,移除对 stream_cast 的特殊处理
- 修改标准容器解析器中的 unsafePtr 为 boxExpr 属性
- 更新相关测试文件中的调用方式和断言
- 替换不安全指针转换为标准容器转换方法
pull/1/head
韩天峰 3 months ago
parent 8deb99c372
commit 26a538680f
  1. 2
      phpunit/code/universal-method-stream-cast-no-arg.php
  2. 2
      phpunit/code/universal-method-stream-unknown-method.php
  3. 17
      src/Php/CompilerBase.php
  4. 8
      src/Php/Parser/StdContainerParser.php
  5. 4
      src/polyfills.php
  6. 22
      tests/aot/stream_method/stream_cast.phpt

@ -3,5 +3,5 @@ function main()
{ {
$tmpfile = tempnam(sys_get_temp_dir(), 'aot'); $tmpfile = tempnam(sys_get_temp_dir(), 'aot');
$fp = fopen($tmpfile, 'w'); $fp = fopen($tmpfile, 'w');
stream_cast()->write('data'); $fp->toStream()->write('data');
} }

@ -2,5 +2,5 @@
function main() function main()
{ {
$tmpfile = tempnam(sys_get_temp_dir(), 'aot'); $tmpfile = tempnam(sys_get_temp_dir(), 'aot');
stream_cast(fopen($tmpfile, 'w'))->unknownMethod(); fopen($tmpfile, 'w')->toStream()->unknownMethod();
} }

@ -2506,7 +2506,7 @@ class CompilerBase extends \PhpAot\Core\Translator
return self::TYPE_BIGFLOAT; return self::TYPE_BIGFLOAT;
} }
} }
if (in_array($name, self::STREAM_FUNCTIONS) || $name === 'stream_cast') { if (in_array($name, self::STREAM_FUNCTIONS)) {
return self::TYPE_STREAM; return self::TYPE_STREAM;
} }
if (count($expr->args) === 1 and $this->isPlaceholderExpr($expr->args[0])) { if (count($expr->args) === 1 and $this->isPlaceholderExpr($expr->args[0])) {
@ -3466,9 +3466,6 @@ class CompilerBase extends \PhpAot\Core\Translator
if (in_array($name, Constants::UNSUPPORTED_FUNCTIONS)) { if (in_array($name, Constants::UNSUPPORTED_FUNCTIONS)) {
$this->fatalError($expr, 'Unsupported function: `' . $name . '`'); $this->fatalError($expr, 'Unsupported function: `' . $name . '`');
} }
if ($name === 'stream_cast') {
return $this->parseExpr($expr->args[0]->value);
}
$nativeFn = $this->findNativeFunction($name); $nativeFn = $this->findNativeFunction($name);
if ($nativeFn) { if ($nativeFn) {
$expr->setAttribute('nativeCall', $nativeFn); $expr->setAttribute('nativeCall', $nativeFn);
@ -6366,8 +6363,8 @@ class CompilerBase extends \PhpAot\Core\Translator
$code .= $this->getIndent(); $code .= $this->getIndent();
if ($type === self::TYPE_STD_ARRAY) { if ($type === self::TYPE_STD_ARRAY) {
$info = $this->context->stdArrays[$name]; $info = $this->context->stdArrays[$name];
if (isset($info['unsafePtr'])) { if (isset($info['boxExpr'])) {
$code .= 'auto &' . $name . '_ref = php_unsafe_cast<' . $info['decl'] . '>(' . $info['unsafePtr'] . ', ' . $info['typeId'] . ');'; $code .= 'auto &' . $name . '_ref = php::toStdContainer<' . $info['decl'] . '>(' . $info['boxExpr'] . ', ' . $info['typeId'] . ');';
} else { } else {
$containerType = 'php::StdContainerBox<' . $info['decl'] . '>'; $containerType = 'php::StdContainerBox<' . $info['decl'] . '>';
$code .= 'php::Var ' . $name . ' = php::Var(new ' . $containerType . '(' . $info['typeId'] . '));' . PHP_EOL; $code .= 'php::Var ' . $name . ' = php::Var(new ' . $containerType . '(' . $info['typeId'] . '));' . PHP_EOL;
@ -6375,8 +6372,8 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
} elseif ($type === self::TYPE_STD_VECTOR) { } elseif ($type === self::TYPE_STD_VECTOR) {
$info = $this->context->stdContainers[$name]; $info = $this->context->stdContainers[$name];
if (isset($info['unsafePtr'])) { if (isset($info['boxExpr'])) {
$code .= 'auto &' . $name . '_ref = php_unsafe_cast<' . $info['decl'] . '>(' . $info['unsafePtr'] . ', ' . $info['typeId'] . ');'; $code .= 'auto &' . $name . '_ref = php::toStdContainer<' . $info['decl'] . '>(' . $info['boxExpr'] . ', ' . $info['typeId'] . ');';
} else { } else {
$containerType = 'php::StdContainerBox<' . $info['decl'] . '>'; $containerType = 'php::StdContainerBox<' . $info['decl'] . '>';
if ($info['size'] !== null) { if ($info['size'] !== null) {
@ -6389,8 +6386,8 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
} elseif ($type === self::TYPE_STD_MAP || $type === self::TYPE_STD_UNORDERED_MAP) { } elseif ($type === self::TYPE_STD_MAP || $type === self::TYPE_STD_UNORDERED_MAP) {
$info = $this->context->stdContainers[$name]; $info = $this->context->stdContainers[$name];
if (isset($info['unsafePtr'])) { if (isset($info['boxExpr'])) {
$code .= 'auto &' . $name . '_ref = php_unsafe_cast<' . $info['decl'] . '>(' . $info['unsafePtr'] . ', ' . $info['typeId'] . ');'; $code .= 'auto &' . $name . '_ref = php::toStdContainer<' . $info['decl'] . '>(' . $info['boxExpr'] . ', ' . $info['typeId'] . ');';
} else { } else {
$containerType = 'php::StdContainerBox<' . $info['decl'] . '>'; $containerType = 'php::StdContainerBox<' . $info['decl'] . '>';
$code .= 'php::Var ' . $name . ' = php::Var(new ' . $containerType . '(' . $info['typeId'] . '));' . PHP_EOL; $code .= 'php::Var ' . $name . ' = php::Var(new ' . $containerType . '(' . $info['typeId'] . '));' . PHP_EOL;

@ -617,8 +617,8 @@ trait StdContainerParser
if ($containerType === 'array') { if ($containerType === 'array') {
$this->addLocalVar($var, self::TYPE_STD_ARRAY); $this->addLocalVar($var, self::TYPE_STD_ARRAY);
$this->parseStdArray($var, $fakeCall); $this->parseStdArray($var, $fakeCall);
$this->context->stdArrays[$var]['unsafePtr'] = $sourceVar; $this->context->stdArrays[$var]['boxExpr'] = $sourceVar;
return '// php_unsafe_cast<' . $this->context->stdArrays[$var]['decl'] . '>(' . $sourceVar . ')'; return '// StdContainer<' . $this->context->stdArrays[$var]['decl'] . '>(' . $sourceVar . ')';
} }
if ($containerType === 'vector') { if ($containerType === 'vector') {
@ -631,8 +631,8 @@ trait StdContainerParser
$this->addLocalVar($var, self::TYPE_STD_UNORDERED_MAP); $this->addLocalVar($var, self::TYPE_STD_UNORDERED_MAP);
$this->parseStdUnorderedMap($var, $fakeCall); $this->parseStdUnorderedMap($var, $fakeCall);
} }
$this->context->stdContainers[$var]['unsafePtr'] = $sourceVar; $this->context->stdContainers[$var]['boxExpr'] = $sourceVar;
return '// php_unsafe_cast<' . $this->context->stdContainers[$var]['decl'] . '>(' . $sourceVar . ')'; return '// StdContainer<' . $this->context->stdArrays[$var]['decl'] . '>(' . $sourceVar . ')';
} }
protected function parseStdMapKeyType(NodeAbstract $expr, string $owner): string protected function parseStdMapKeyType(NodeAbstract $expr, string $owner): string

@ -89,7 +89,3 @@ function any(mixed $var): mixed
return $var; return $var;
} }
function stream_cast($stream)
{
return $stream;
}

@ -1,5 +1,5 @@
--TEST-- --TEST--
stream_cast() pseudo-function for stream type casting toStream() keyword method for stream type casting
--FILE-- --FILE--
<?php <?php
@ -7,36 +7,36 @@ function main()
{ {
require __DIR__ . '/../../../src/Assert.php'; require __DIR__ . '/../../../src/Assert.php';
// Test 1: stream_cast identity — on an already-inferred stream variable // Test 1: toStream() on an already-inferred stream variable
$tmpfile = tempnam(sys_get_temp_dir(), 'aot'); $tmpfile = tempnam(sys_get_temp_dir(), 'aot');
$fp = fopen($tmpfile, 'w+'); $fp = fopen($tmpfile, 'w+');
$fp->write("hello world"); $fp->write("hello world");
$fp->seek(0); $fp->seek(0);
$data = stream_cast($fp)->read(5); $data = $fp->toStream()->read(5);
var_dump($data); var_dump($data);
$fp->close(); $fp->close();
// Test 2: stream_cast on array elements where type isn't known // Test 2: toStream() on array elements where type isn't known
$pipes = []; $pipes = [];
$pipes[0] = fopen($tmpfile, 'w'); $pipes[0] = fopen($tmpfile, 'w');
$w = stream_cast($pipes[0]); $w = $pipes[0]->toStream();
$w->write("test data from pipe"); $w->write("test data from pipe");
$w->close(); $w->close();
$pipes[1] = fopen($tmpfile, 'r'); $pipes[1] = fopen($tmpfile, 'r');
$r = stream_cast($pipes[1]); $r = $pipes[1]->toStream();
$data2 = $r->read(1024); $data2 = $r->read(1024);
var_dump($data2); var_dump($data2);
$r->close(); $r->close();
// Test 3: stream_cast in expression context (method chaining) // Test 3: toStream() in expression context (method chaining)
$fp2 = fopen($tmpfile, 'w'); $fp2 = fopen($tmpfile, 'w');
stream_cast($fp2)->write("chain test"); $fp2->toStream()->write("chain test");
stream_cast($fp2)->close(); $fp2->toStream()->close();
$fp3 = fopen($tmpfile, 'r'); $fp3 = fopen($tmpfile, 'r');
var_dump(stream_cast($fp3)->read(10)); var_dump($fp3->toStream()->read(10));
stream_cast($fp3)->close(); $fp3->toStream()->close();
unlink($tmpfile); unlink($tmpfile);
echo "OK\n"; echo "OK\n";

Loading…
Cancel
Save