Skip to content

Commit caaa9ea

Browse files
committed
fix: ChangeCtxAndCallFuncValue parent::A 后内部再调用 parent::B 上下文没有切换导致死循环
1 parent 8d44f93 commit caaa9ea

File tree

2 files changed

+80
-5
lines changed

2 files changed

+80
-5
lines changed

node/call_parent_method.go

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,55 @@ func (pe *CallParentMethod) GetValue(ctx data.Context) (data.GetValue, data.Cont
4343
// 获取父类方法
4444
method, has := parentClass.GetMethod(pe.Method)
4545
if !has {
46-
return nil, data.NewErrorThrow(pe.GetFrom(), errors.New(fmt.Sprintf("父类 %s 没有方法 %s", parentClassName, pe.Method)))
46+
return nil, data.NewErrorThrow(pe.GetFrom(), fmt.Errorf("父类 %s 没有方法 %s", parentClassName, pe.Method))
4747
}
4848

4949
// 检查方法访问权限
5050
if method.GetModifier() == data.ModifierPrivate {
51-
return nil, data.NewErrorThrow(pe.GetFrom(), errors.New(fmt.Sprintf("父类方法 %s 是私有的,无法访问", pe.Method)))
51+
return nil, data.NewErrorThrow(pe.GetFrom(), fmt.Errorf("父类方法 %s 是私有的,无法访问", pe.Method))
5252
}
5353

54-
return data.NewFuncValue(method), nil
54+
return &ChangeCtxAndCallFuncValue{ctx: classCtx, fun: method}, nil
55+
}
56+
57+
// ChangeCtxAndCallFuncValue parent::A 后内部再调用 parent::B 上下文没有切换导致死循环
58+
type ChangeCtxAndCallFuncValue struct {
59+
ctx *data.ClassMethodContext
60+
fun data.Method
61+
}
62+
63+
// parentMethodFunc 适配器:将 data.Method 包装为 data.FuncStmt,并在调用时切换到父类上下文
64+
type parentMethodFunc struct {
65+
baseCtx *data.ClassMethodContext
66+
method data.Method
67+
}
68+
69+
func (p *parentMethodFunc) GetName() string { return p.method.GetName() }
70+
func (p *parentMethodFunc) GetParams() []data.GetValue { return p.method.GetParams() }
71+
func (p *parentMethodFunc) GetVariables() []data.Variable { return p.method.GetVariables() }
72+
func (p *parentMethodFunc) Call(callCtx data.Context) (data.GetValue, data.Control) {
73+
// 取父类
74+
if p.baseCtx == nil || p.baseCtx.Class == nil || p.baseCtx.Class.GetExtend() == nil {
75+
return nil, data.NewErrorThrow(nil, errors.New("当前类没有父类"))
76+
}
77+
78+
parentName := *p.baseCtx.Class.GetExtend()
79+
vm := callCtx.GetVM()
80+
parentClass, acl := vm.GetOrLoadClass(parentName)
81+
if acl != nil {
82+
return nil, acl
83+
}
84+
85+
// 使用调用时创建好的变量上下文(callCtx),但切换到父类的方法上下文,保持同一个对象实例
86+
newCtx := &data.ClassMethodContext{ClassValue: &data.ClassValue{
87+
ObjectValue: p.baseCtx.ObjectValue,
88+
Class: parentClass,
89+
Context: callCtx,
90+
}}
91+
92+
return p.method.Call(newCtx)
93+
}
94+
95+
func (c *ChangeCtxAndCallFuncValue) GetValue(ctx data.Context) (data.GetValue, data.Control) {
96+
return data.NewFuncValue(&parentMethodFunc{baseCtx: c.ctx, method: c.fun}), nil
5597
}

script.zy

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
1+
namespace tests\obj;
12

2-
$n = 123;
3-
echo <div :title="call({$n})"></div>;
3+
class B extends Exception {
4+
public function __construct($message) {
5+
parent::__construct($message);
6+
}
7+
}
8+
9+
class TestException extends B {
10+
public function __construct($message) {
11+
parent::__construct($message);
12+
}
13+
}
14+
15+
class Err {
16+
public function one(){
17+
$this->two();
18+
}
19+
20+
public function two(){
21+
throw new TestException('8888');
22+
}
23+
}
24+
25+
try {
26+
$obj = new Err();
27+
$a = $obj->one();
28+
} catch (Exception $e) {
29+
Log::info('开始捕获异常');
30+
$msg = $e->getMessage();
31+
if ($msg != '8888') {
32+
Log::fatal('自定义异常抛出 error');
33+
} else {
34+
Log::info('自定义异常抛出成功');
35+
}
36+
}

0 commit comments

Comments
 (0)