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');
$fp = fopen($tmpfile, 'w');
stream_cast()->write('data');
$fp->toStream()->write('data');
}

@ -2,5 +2,5 @@
function main()
{
$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;
}
}
if (in_array($name, self::STREAM_FUNCTIONS) || $name === 'stream_cast') {
if (in_array($name, self::STREAM_FUNCTIONS)) {
return self::TYPE_STREAM;
}
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)) {
$this->fatalError($expr, 'Unsupported function: `' . $name . '`');
}
if ($name === 'stream_cast') {
return $this->parseExpr($expr->args[0]->value);
}
$nativeFn = $this->findNativeFunction($name);
if ($nativeFn) {
$expr->setAttribute('nativeCall', $nativeFn);
@ -6366,8 +6363,8 @@ class CompilerBase extends \PhpAot\Core\Translator
$code .= $this->getIndent();
if ($type === self::TYPE_STD_ARRAY) {
$info = $this->context->stdArrays[$name];
if (isset($info['unsafePtr'])) {
$code .= 'auto &' . $name . '_ref = php_unsafe_cast<' . $info['decl'] . '>(' . $info['unsafePtr'] . ', ' . $info['typeId'] . ');';
if (isset($info['boxExpr'])) {
$code .= 'auto &' . $name . '_ref = php::toStdContainer<' . $info['decl'] . '>(' . $info['boxExpr'] . ', ' . $info['typeId'] . ');';
} else {
$containerType = 'php::StdContainerBox<' . $info['decl'] . '>';
$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) {
$info = $this->context->stdContainers[$name];
if (isset($info['unsafePtr'])) {
$code .= 'auto &' . $name . '_ref = php_unsafe_cast<' . $info['decl'] . '>(' . $info['unsafePtr'] . ', ' . $info['typeId'] . ');';
if (isset($info['boxExpr'])) {
$code .= 'auto &' . $name . '_ref = php::toStdContainer<' . $info['decl'] . '>(' . $info['boxExpr'] . ', ' . $info['typeId'] . ');';
} else {
$containerType = 'php::StdContainerBox<' . $info['decl'] . '>';
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) {
$info = $this->context->stdContainers[$name];
if (isset($info['unsafePtr'])) {
$code .= 'auto &' . $name . '_ref = php_unsafe_cast<' . $info['decl'] . '>(' . $info['unsafePtr'] . ', ' . $info['typeId'] . ');';
if (isset($info['boxExpr'])) {
$code .= 'auto &' . $name . '_ref = php::toStdContainer<' . $info['decl'] . '>(' . $info['boxExpr'] . ', ' . $info['typeId'] . ');';
} else {
$containerType = 'php::StdContainerBox<' . $info['decl'] . '>';
$code .= 'php::Var ' . $name . ' = php::Var(new ' . $containerType . '(' . $info['typeId'] . '));' . PHP_EOL;

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

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

@ -1,5 +1,5 @@
--TEST--
stream_cast() pseudo-function for stream type casting
toStream() keyword method for stream type casting
--FILE--
<?php
@ -7,36 +7,36 @@ function main()
{
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');
$fp = fopen($tmpfile, 'w+');
$fp->write("hello world");
$fp->seek(0);
$data = stream_cast($fp)->read(5);
$data = $fp->toStream()->read(5);
var_dump($data);
$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[0] = fopen($tmpfile, 'w');
$w = stream_cast($pipes[0]);
$w = $pipes[0]->toStream();
$w->write("test data from pipe");
$w->close();
$pipes[1] = fopen($tmpfile, 'r');
$r = stream_cast($pipes[1]);
$r = $pipes[1]->toStream();
$data2 = $r->read(1024);
var_dump($data2);
$r->close();
// Test 3: stream_cast in expression context (method chaining)
// Test 3: toStream() in expression context (method chaining)
$fp2 = fopen($tmpfile, 'w');
stream_cast($fp2)->write("chain test");
stream_cast($fp2)->close();
$fp2->toStream()->write("chain test");
$fp2->toStream()->close();
$fp3 = fopen($tmpfile, 'r');
var_dump(stream_cast($fp3)->read(10));
stream_cast($fp3)->close();
var_dump($fp3->toStream()->read(10));
$fp3->toStream()->close();
unlink($tmpfile);
echo "OK\n";

Loading…
Cancel
Save