【问题标题】:Haxe / hscript - Prevent exposing certain methods to scriptsHaxe / hscript - 防止将某些方法暴露给脚本
【发布时间】:2025-12-31 04:10:12
【问题描述】:

所以,我创建了包含所有静态方法的“接口类”,我希望将其公开给hscript 脚本。它看起来像这样:

package com.application.interfaces.Terrain;

import com.application.TerrainCore

class Terrain {

    private static var terrain:TerrainCore;

    public static function _init(inTerrain:TerrainCore):Void {
        terrain = inTerrain;
    }

    public static function test(s:Int):Void {
        terrain.test(s);
    }
}

问题是,我需要以某种方式设置terrain 对象,但我不希望它暴露给脚本。我用

公开整个课程
var interp = new Interp();
var module = Type.resolveClass("com.application.interfaces.Terrain");
interp.variables.set("Terrain", module)

这个想法是在hscript.Interp 中覆盖方法call,因此它不会执行任何名为_init 的方法,但我不知道该怎么做。原来的call 方法是这样的:

function call( o : Dynamic, f : Dynamic, args : Array<Dynamic> ) : Dynamic {
    return Reflect.callMethod(o,f,args);
}

【问题讨论】:

    标签: haxe hxcpp


    【解决方案1】:

    您可以使用 Terrain 的类实例而不是使用静态成员吗​​?例如:

    interp.variables.set("Terrain", new Terrain(new TerrainCore()));
    

    脚本用户不会知道他们使用的是静态方法还是实例方法,因为它仍然可以通过以下方式访问:

    Terrain.test(123);
    

    在脚本中。

    另一种选择(基于 clemos)是使用 rtti 来计算允许的内容(而不是维护它的列表),例如:

    Terrain._init(new TerrainCore());
    

    _init 现在是一个私有函数,所以你需要从你的调用类中 @:allow 它(见下文),你需要用 @:rtti 注释,这样你就可以在运行时获取有关函数的信息,所以地形现在看起来像:

    @:rtti
    class Terrain {
    
        private static var terrain:TerrainCore;
    
        @:allow(test.hscript.demo.Main)
        private static function _init(inTerrain:TerrainCore):Void {
            terrain = inTerrain;
        }
    
        public static function test(s:Int):Void {
            terrain.test(s);
        }
    }
    

    最后,脚本 interp fcall 现在尊重一个字段是公共的还是私有的,即:

    public override function fcall(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic 
        var rtti = haxe.rtti.Rtti.getRtti(o);
        for (field in rtti.statics) {
            if (field.name == f && field.isPublic == false) {
                error(EInvalidAccess(f));
            }
        }
        return super.fcall(o, f, args);
    }
    

    值得注意的是,出于显而易见的原因,我使用了statics 而不是fields。我也不确定这会对循环和 rtti 造成什么开销。

    【讨论】:

    • 是的,我首先不应该在这里使用静态成员,我没有想到我可以以某种方式使用类实例。谢谢你。顺便说一句,@clemos 和您的其他解决方案也是可能的,但在我的情况下,使用实例似乎更优雅的解决方案,我不应该对我目前正在做的事情使用静态方法......
    • 是的,你们都是对的。此外,您可能希望在编译时和“解释时”具有不同的访问权限;如果我是你,我会使用元数据(例如 @:hscriptAccess('public'))来控制解释时的访问,而不是 public / private,而是用于编译时:haxe.org/manual/lf-metadata.html
    【解决方案2】:

    我认为您应该覆盖 fcall,因为 call 仅用于*调用:

    https://github.com/HaxeFoundation/hscript/blob/master/hscript/Interp.hx#L328-L331

    过滤f 参数应该很容易,例如:

    if ( FORBIDDEN_FIELDS.indexOf( f ) > -1 ) throw EInvalidAccess( f );
    

    if ( f.indexOf('_') == 0 ) throw EInvalidAccess( f );
    

    【讨论】:

      最近更新 更多