- Replace direct string concatenation with formatCppLineComment method - Add proper line wrapping for multi-line comments in generated code - Apply consistent comment formatting across function calls, expressions and method calls - Introduce formatCppLineComment helper to handle comment formatting logic - Update all comment generation points to use the new standardized approach - Add test cases for ThinkPHP cookie, environment and service patterns - Add test case for trait method return by reference functionalitypull/16/head
parent
be5e553bf7
commit
441091fbc5
5 changed files with 415 additions and 7 deletions
@ -0,0 +1,39 @@ |
|||||||
|
--TEST-- |
||||||
|
Return value by trait (method) |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
Trait T1 |
||||||
|
{ |
||||||
|
public function &getRefValue() |
||||||
|
{ |
||||||
|
return $this->value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class Test |
||||||
|
{ |
||||||
|
use T1; |
||||||
|
|
||||||
|
private $value = 1; |
||||||
|
|
||||||
|
public function getValue() |
||||||
|
{ |
||||||
|
return $this->value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main() |
||||||
|
{ |
||||||
|
$test = new Test; |
||||||
|
var_dump($test->getValue()); |
||||||
|
var_dump($refValue = &$test->getRefValue()); |
||||||
|
$refValue = 2; |
||||||
|
var_dump($test->getValue()); |
||||||
|
var_dump($test->getRefValue()); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
int(1) |
||||||
|
int(1) |
||||||
|
int(2) |
||||||
|
int(2) |
||||||
@ -0,0 +1,66 @@ |
|||||||
|
--TEST-- |
||||||
|
ThinkPHP App pattern: array_filter with dynamic instanceof service lookup |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
class ThinkServiceBase |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
class ThinkLoggerService extends ThinkServiceBase |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
class ThinkCacheService extends ThinkServiceBase |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
class ThinkAppServiceLike |
||||||
|
{ |
||||||
|
private array $services = []; |
||||||
|
|
||||||
|
public function register(object $service): void |
||||||
|
{ |
||||||
|
$this->services[] = $service; |
||||||
|
} |
||||||
|
|
||||||
|
public function getService(object|string $service): ?object |
||||||
|
{ |
||||||
|
$name = is_string($service) ? $service : $service::class; |
||||||
|
return array_values(array_filter($this->services, function ($value) use ($name) { |
||||||
|
return $value instanceof $name; |
||||||
|
}, ARRAY_FILTER_USE_BOTH))[0] ?? null; |
||||||
|
} |
||||||
|
|
||||||
|
public function boot(): array |
||||||
|
{ |
||||||
|
$booted = []; |
||||||
|
array_walk($this->services, function ($service) use (&$booted) { |
||||||
|
$booted[] = $service::class; |
||||||
|
}); |
||||||
|
return $booted; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$app = new ThinkAppServiceLike(); |
||||||
|
$app->register(new ThinkLoggerService()); |
||||||
|
$app->register(new ThinkCacheService()); |
||||||
|
|
||||||
|
var_dump($app->getService(ThinkCacheService::class)::class); |
||||||
|
var_dump($app->getService(new ThinkLoggerService())::class); |
||||||
|
var_dump($app->getService(DateTimeImmutable::class)); |
||||||
|
var_dump($app->boot()); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
string(17) "ThinkCacheService" |
||||||
|
string(18) "ThinkLoggerService" |
||||||
|
NULL |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
string(18) "ThinkLoggerService" |
||||||
|
[1]=> |
||||||
|
string(17) "ThinkCacheService" |
||||||
|
} |
||||||
@ -0,0 +1,147 @@ |
|||||||
|
--TEST-- |
||||||
|
ThinkPHP Cookie pattern: option normalization, destructuring and trailing call args |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
class ThinkCookieRequestLike |
||||||
|
{ |
||||||
|
public array $cookie = []; |
||||||
|
|
||||||
|
public function setCookie(string $name, mixed $value): void |
||||||
|
{ |
||||||
|
$this->cookie[$name] = $value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class ThinkCookieLike |
||||||
|
{ |
||||||
|
private array $config = [ |
||||||
|
'expire' => 0, |
||||||
|
'path' => '/', |
||||||
|
'domain' => '', |
||||||
|
'secure' => false, |
||||||
|
'httponly' => false, |
||||||
|
'samesite' => '', |
||||||
|
]; |
||||||
|
private array $cookie = []; |
||||||
|
public array $saved = []; |
||||||
|
|
||||||
|
public function __construct(private ThinkCookieRequestLike $request, array $config = []) |
||||||
|
{ |
||||||
|
$this->config = array_merge($this->config, array_change_key_case($config)); |
||||||
|
} |
||||||
|
|
||||||
|
public function set(string $name, string $value, mixed $option = null): void |
||||||
|
{ |
||||||
|
if ($option !== null) { |
||||||
|
if (is_numeric($option) || $option instanceof DateTimeInterface) { |
||||||
|
$option = ['expire' => $option]; |
||||||
|
} |
||||||
|
$config = array_merge($this->config, array_change_key_case($option)); |
||||||
|
} else { |
||||||
|
$config = $this->config; |
||||||
|
} |
||||||
|
|
||||||
|
if ($config['expire'] instanceof DateTimeInterface) { |
||||||
|
$expire = $config['expire']->getTimestamp(); |
||||||
|
} else { |
||||||
|
$expire = !empty($config['expire']) ? 1000 + intval($config['expire']) : 0; |
||||||
|
} |
||||||
|
|
||||||
|
$this->setCookie($name, $value, $expire, $config); |
||||||
|
$this->request->setCookie($name, $value); |
||||||
|
} |
||||||
|
|
||||||
|
public function forever(string $name, string $value = '', mixed $option = null): void |
||||||
|
{ |
||||||
|
if (is_null($option) || is_numeric($option)) { |
||||||
|
$option = []; |
||||||
|
} |
||||||
|
|
||||||
|
$option['expire'] = 315360000; |
||||||
|
$this->set($name, $value, $option); |
||||||
|
} |
||||||
|
|
||||||
|
private function setCookie(string $name, string $value, int $expire, array $option = []): void |
||||||
|
{ |
||||||
|
$this->cookie[$name] = [$value, $expire, $option]; |
||||||
|
} |
||||||
|
|
||||||
|
public function save(): void |
||||||
|
{ |
||||||
|
foreach ($this->cookie as $name => $val) { |
||||||
|
[$value, $expire, $option] = $val; |
||||||
|
$this->saveCookie( |
||||||
|
(string) $name, |
||||||
|
$value, |
||||||
|
$expire, |
||||||
|
$option['path'], |
||||||
|
$option['domain'], |
||||||
|
(bool) $option['secure'], |
||||||
|
(bool) $option['httponly'], |
||||||
|
$option['samesite'], |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private function saveCookie(string $name, string $value, int $expire, string $path, string $domain, bool $secure, bool $httponly, string $samesite): void |
||||||
|
{ |
||||||
|
$this->saved[$name] = compact('value', 'expire', 'path', 'domain', 'secure', 'httponly', 'samesite'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$request = new ThinkCookieRequestLike(); |
||||||
|
$cookie = new ThinkCookieLike($request, ['SameSite' => 'lax', 'Secure' => true]); |
||||||
|
$cookie->set('token', 'abc', new DateTimeImmutable('@42')); |
||||||
|
$cookie->forever('remember', 'yes', ['HttpOnly' => true]); |
||||||
|
$cookie->save(); |
||||||
|
|
||||||
|
var_dump($request->cookie); |
||||||
|
var_dump($cookie->saved); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
array(2) { |
||||||
|
["token"]=> |
||||||
|
string(3) "abc" |
||||||
|
["remember"]=> |
||||||
|
string(3) "yes" |
||||||
|
} |
||||||
|
array(2) { |
||||||
|
["token"]=> |
||||||
|
array(7) { |
||||||
|
["value"]=> |
||||||
|
string(3) "abc" |
||||||
|
["expire"]=> |
||||||
|
int(42) |
||||||
|
["path"]=> |
||||||
|
string(1) "/" |
||||||
|
["domain"]=> |
||||||
|
string(0) "" |
||||||
|
["secure"]=> |
||||||
|
bool(true) |
||||||
|
["httponly"]=> |
||||||
|
bool(false) |
||||||
|
["samesite"]=> |
||||||
|
string(3) "lax" |
||||||
|
} |
||||||
|
["remember"]=> |
||||||
|
array(7) { |
||||||
|
["value"]=> |
||||||
|
string(3) "yes" |
||||||
|
["expire"]=> |
||||||
|
int(315361000) |
||||||
|
["path"]=> |
||||||
|
string(1) "/" |
||||||
|
["domain"]=> |
||||||
|
string(0) "" |
||||||
|
["secure"]=> |
||||||
|
bool(true) |
||||||
|
["httponly"]=> |
||||||
|
bool(true) |
||||||
|
["samesite"]=> |
||||||
|
string(3) "lax" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,136 @@ |
|||||||
|
--TEST-- |
||||||
|
ThinkPHP Env pattern: ArrayAccess, magic accessors and nested env flattening |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
class ThinkEnvLike implements ArrayAccess |
||||||
|
{ |
||||||
|
private array $data = []; |
||||||
|
private array $convert = [ |
||||||
|
'true' => true, |
||||||
|
'false' => false, |
||||||
|
'off' => false, |
||||||
|
'on' => true, |
||||||
|
]; |
||||||
|
|
||||||
|
public function get(?string $name = null, mixed $default = null): mixed |
||||||
|
{ |
||||||
|
if ($name === null) { |
||||||
|
return $this->data; |
||||||
|
} |
||||||
|
|
||||||
|
$name = strtoupper(str_replace('.', '_', $name)); |
||||||
|
if (isset($this->data[$name])) { |
||||||
|
$result = $this->data[$name]; |
||||||
|
if (is_string($result) && isset($this->convert[$result])) { |
||||||
|
return $this->convert[$result]; |
||||||
|
} |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
return $default; |
||||||
|
} |
||||||
|
|
||||||
|
public function set(mixed $env, mixed $value = null): void |
||||||
|
{ |
||||||
|
if (is_array($env)) { |
||||||
|
$env = array_change_key_case($env, CASE_UPPER); |
||||||
|
foreach ($env as $key => $val) { |
||||||
|
if (is_array($val)) { |
||||||
|
foreach ($val as $k => $v) { |
||||||
|
if (is_string($k)) { |
||||||
|
$this->data[$key . '_' . strtoupper($k)] = $v; |
||||||
|
} else { |
||||||
|
$this->data[$key][$k] = $v; |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
$this->data[$key] = $val; |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
$name = strtoupper(str_replace('.', '_', $env)); |
||||||
|
$this->data[$name] = $value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function has(string $name): bool |
||||||
|
{ |
||||||
|
return !is_null($this->get($name)); |
||||||
|
} |
||||||
|
|
||||||
|
public function __set(string $name, mixed $value): void |
||||||
|
{ |
||||||
|
$this->set($name, $value); |
||||||
|
} |
||||||
|
|
||||||
|
public function __get(string $name): mixed |
||||||
|
{ |
||||||
|
return $this->get($name); |
||||||
|
} |
||||||
|
|
||||||
|
public function __isset(string $name): bool |
||||||
|
{ |
||||||
|
return $this->has($name); |
||||||
|
} |
||||||
|
|
||||||
|
public function offsetSet(mixed $name, mixed $value): void |
||||||
|
{ |
||||||
|
$this->set($name, $value); |
||||||
|
} |
||||||
|
|
||||||
|
public function offsetExists(mixed $name): bool |
||||||
|
{ |
||||||
|
return $this->__isset($name); |
||||||
|
} |
||||||
|
|
||||||
|
public function offsetUnset(mixed $name): void |
||||||
|
{ |
||||||
|
throw new Exception('not support: unset'); |
||||||
|
} |
||||||
|
|
||||||
|
public function offsetGet(mixed $name): mixed |
||||||
|
{ |
||||||
|
return $this->get($name); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$env = new ThinkEnvLike(); |
||||||
|
$env->set([ |
||||||
|
'app' => ['debug' => 'true', 'hosts' => ['a', 'b']], |
||||||
|
'feature' => 'off', |
||||||
|
]); |
||||||
|
$env['database.host'] = 'localhost'; |
||||||
|
$env->cache_enabled = 'on'; |
||||||
|
|
||||||
|
var_dump($env->get('app.debug')); |
||||||
|
var_dump($env['feature']); |
||||||
|
var_dump($env->database_host); |
||||||
|
var_dump(isset($env->cache_enabled)); |
||||||
|
var_dump($env->get()); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
bool(true) |
||||||
|
bool(false) |
||||||
|
string(9) "localhost" |
||||||
|
bool(true) |
||||||
|
array(5) { |
||||||
|
["APP_DEBUG"]=> |
||||||
|
string(4) "true" |
||||||
|
["APP_HOSTS"]=> |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
string(1) "a" |
||||||
|
[1]=> |
||||||
|
string(1) "b" |
||||||
|
} |
||||||
|
["FEATURE"]=> |
||||||
|
string(3) "off" |
||||||
|
["DATABASE_HOST"]=> |
||||||
|
string(9) "localhost" |
||||||
|
["CACHE_ENABLED"]=> |
||||||
|
string(2) "on" |
||||||
|
} |
||||||
Loading…
Reference in new issue