asmblah / uniter

🎉 PHP in the browser and Node.js => Docs: https://phptojs.com/
https://asmblah.github.io/uniter/
Other
446 stars 42 forks source link

Superglobals #32

Closed IngwiePhoenix closed 8 years ago

IngwiePhoenix commented 8 years ago

While looking at this project: https://github.com/js-cookie/js-cookie ... i realized, Uniter never actually seemed to introduce superglobals.

So I would like to ask, how one would set up the superglobals? Say I want to emulate $COOKIE with this project above, that would mean I'd need:

I can see this being implemented as part of my uniter-stl, which I will likely re-write soon to adapt a bit better and to a nicer structure. But for this to work in general, I'd still need to know how to setup a superglobal, and especially with a way to add getter and setter.

The other superglobals are:

I could see these being implemented by making them all be raw associative arrays - aka. empty JS objects - by default - which they really are - and giving the user an API to set their value.

// For example:
phpruntime.setSuper("$_SERVER", {HTTP_CONTENT_TYPE: "text/plain"});
phpruntime.setSuper("$_ENV", process.env);
phpruntime.setSuper("$argv", process.argv || ["--some", "arg"]);

A pseudo testcase (jasmine/expect):

var _ = require("microdash");

var object_globals = [
    "$_GET", "$_POST", "$_REQUEST", "$_FILES",
    "$_SERVER", "$_ENV", "$_SESSION"
];

describe("PHPRuntime", function(){
    describe(".setSuper", function(){
        object_globals.forEach(function(globalName){
            it("only accepts an object for: "+globalName, function(){
                var phpruntime = this.phpruntime; // get php runtime
                expect(function() {
                    phpruntime.setSuper(globalName, {foo: "bar"});
                }).not.toThrow; // a TypeErrpr exception
            });
        });

        it("should only accept an array for $argv", function(){
            var phpruntime = this.phpruntime;
            expect(function(){
                phpruntime.setSuper("$argv", {});
            }).toThrow;
            expect(function(){
                phpruntime.setSuper("$argv", []);
            }).not.toThrow;
        });

        it("should automatically match $argc to $argv", function(){
            var phpruntime = this.phpruntime;
            var argv = ["uniter", "foo.php", "--arg1", "--arg2=withSomething"];

            phpruntime.setSuper("$argv", argv);

            expect(phpruntime.getSuper("$argc").length).isEqual(argv.length);
        });

        it("should prevent manipulation of $argc", function(){
            var phpruntime = this.phpruntime;
            expect(function(){
                phpruntime.setSuper("$argc", /* it's over */9000);
            }).toThrow;
        });
    });
});

( Yup, im geting used to unit testing right there! :) )

IngwiePhoenix commented 8 years ago

I just realized my test didnt mention cookies - but, you get what i meant. :)

asmblah commented 8 years ago

@IngwiePhoenix I've just published PHPCore v3.13.0 with support for super globals :smile: They can be set with the method <Engine>.setSuperGlobal('<name>', '<native JS value>');. I have a patch to add support for 'accessor' superglobals in dev at the moment, which would be needed for your should automatically match $argc to $argv scenario, but it's not quite ready yet.

Note that the name is without the leading dollar-sign character.

asmblah commented 8 years ago

Here's an example from the tests: https://github.com/uniter/phpcore/blob/master/test/integration/superGlobalTest.js#L34

IngwiePhoenix commented 8 years ago

Nice! Looks good to me. :)

asmblah commented 8 years ago

@IngwiePhoenix I've just published PHPCore v3.14.0, now with support for accessor superglobals with getters and setters using <engine>.setSuperGlobalAccessor('<name>', <getter>, <setter>);. Here's an example from the tests: https://github.com/uniter/phpcore/blob/master/test/integration/superGlobalTest.js#L68

asmblah commented 8 years ago

Based on this, I'm considering deprecating the current <Engine>.expose(...) API and adding a new set of methods for each operation instead: <Engine>.setVariable(...), <Engine>.getVariable(...), <Engine>.defineClass(...), <Engine>.defineFunction(...) etc.

(Non-superglobal) variables could then have accessors too, eg.: <Engine>.setVariableAccessor(...)

IngwiePhoenix commented 8 years ago

You could keep .expose() for BC untill the next major bump and have it decide an action according to to the type of input. Just an idea :)

asmblah commented 8 years ago

Yep, that's the plan, sorry, that's what I meant by 'deprecate' rather than remove. :smile: I think .expose(...) definitely should be removed eventually though, to make it more obvious what's going on.

asmblah commented 8 years ago

Hi @IngwiePhoenix,

Now that superglobals have been added as a feature, and ArrayAccess support has been added, is there anything else you need to resolve this issue?

IngwiePhoenix commented 8 years ago

I doubt there is anything left from here on out. :)

As such, Ill also close the issue.

Thanks a lot for the implementations!