Вызовите метод ColdFusion с явным получателем

Я пытаюсь написать миксин в ColdFusion.

ExampleMixin.cfc:

component {
    remote void function mixin(component, methodName) {
        var original = component[methodName];
        component[methodName] = function() {
            writeOutput("Mixin!");
            return original(arguments);
        };
    }
}

test.cfc:

component {
    new ExampleMixin().mixin(this, 'foo');

    remote string function foo() {
        return getOutput();
    }

    private string function getOutput() {
        return "Hello, World!";
    }
}

Бег foo выдает ошибку, Variable GETOUTPUT is undefined., Если я закомментирую new ExampleMixin().mixin(this, 'foo');работает нормально.

Похоже, когда foo запускается из оболочки, он работает не в нужном контексте. В JavaScript можно написать foo.call(component, ...arguments) чтобы исправить это. Есть ли эквивалент в ColdFusion?

1 ответ

Решение

ColdFusion использует как this а также variables Области для хранения ссылок на функции. Используемая ссылка зависит от того, как вызывается функция. Если функция вызывается от родного брата, variables ссылка используется. Если функция вызывается извне, то this ссылка используется.

Следующий код использует базовый класс для обеспечения функциональности mixin.$mixin Функция принимает экземпляр компонента и внедряет все его функции. Если происходит конфликт имен, обертка сначала вызовет mixin, а затем оригинальную функцию. Я генерирую новые имена функций как для исходных функций, так и для функций mixin, поэтому ссылки могут быть установлены в обеих областях.

Это было проверено на Lucee 5.2.8.50.

mixable.cfc

component {
    function $mixin(obj) {
        var meta = getComponentMetadata(obj);

        for(var func in meta.functions) {
            if(structKeyExists(this, func.name)) {
                var orig = func.name & replace(createUUID(), '-', '', 'all');
                var injected = func.name & replace(createUUID(), '-', '', 'all');

                this[orig] = this[func.name];
                variables[orig] = this[func.name];

                this[injected] = obj[func.name];
                variables[injected] = obj[func.name];

                var wrapper = function() {
                    this[injected](argumentCollection=arguments);
                    return this[orig](argumentCollection=arguments);
                };
                this[func.name] = wrapper;
                variables[func.name] = wrapper;
            } else {
                this[func.name] = obj[func.name];
                return variables[func.name] = obj[func.name];
            }
        }
    }
}

test.cfc

component extends="mixable" {
    remote function foo() {
        writeOutput("foo(), calling bar()<br>");
        bar();
    }

    private function bar() {
        writeOutput("bar()<br>");
    }
}

mixin.cfc

component {
    function foo() {
        writeOutput("foo mixin, calling bar()<br>");
        bar();
    }

    function myfunc() {
        writeOutput("myfunc()<br>");
    }
}

index.cfm

<cfscript>
t = new test();
t.$mixin(new mixin());
t.myfunc();
t.foo();
</cfscript>

Выход

myfunc()
foo mixin, calling bar()
bar()
foo(), calling bar()
bar()
Другие вопросы по тегам