peachpie icon indicating copy to clipboard operation
peachpie copied to clipboard

Magic methods not working as expected

Open luizzaiats opened this issue 2 years ago • 4 comments

On PHP, we can instantiate a stdClass and set properties dynamically as follow:

$obj = new stdClass(); $obj->name = 'My Name'; $obj->time = time();

On PeachPie is there a way to do that? I've tried:

dynamic _obj = new stdClass(); _obj.name = "My Name";

But I got the following error:

Unhandled exception. Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Pchp.Core.PhpValue' does not contain a definition for 'name'

Am I missing something?

luizzaiats avatar Mar 28 '23 23:03 luizzaiats

This works with PeachPie in PHP code, because the PeachPie compiler takes care of it. So you can compile this PHP code with PeachPie.

However, PeachPie/C# runtime does not implement dynamic approach yet, so you can't do it from C#.

jakubmisek avatar Mar 29 '23 11:03 jakubmisek

Also, it's not quite a magic method. It's a dynamic property not involving __get or __call.

Magic methods won't work through dynamic in C# either.

We'd have to implement IDynamicMetaObjectProvider.

jakubmisek avatar Mar 29 '23 11:03 jakubmisek

@jakubmisek thank you for the clarification ;)

I am very interested on using the PHP/C# interop, using PHP objects on C#/Blazor. I already have a small REST API written in PHP using StraightFramework and RedbeanPHP so I'll try to run this REST API (on top of PeachPie) and Blazor making the calls to it over HTTP requests.

Investigating here, I was able to use RedbeanPHP on C# as follow:

ctx.Call("R::setup", "sqlite:./dbfile.db");
            
dynamic _user = ctx.Call("R::dispense", "user");
_user.Object.__set("username", "luiz.zaiats");
            
dynamic _profession = ctx.Call("R::dispense", "profession");
_profession.Object.__set("name", "Programmer");

_user.Object.__set("profession", _profession);

ctx.Call("R::store", _user);

The above code works perfectly, but when I try to load data and update, something is messy on the bean itself not allowing me to update the object:

var users = ctx.Call("R::find", "user");
foreach(var kv in users) {
    RedBeanPHP.OODBBean v = kv.Value.Object as RedBeanPHP.OODBBean;
    Console.WriteLine(v.__get("username"));

    RedBeanPHP.OODBBean p = v.__get("profession").AsObject() as RedBeanPHP.OODBBean;
    Console.WriteLine(p.__get("name"));

    p.__set("name", "Updated Programmer");
    Console.WriteLine(p.__get("name"));

    ctx.Call("R::store", (PhpValue)kv.Value); // this operation throws Unhandled exception. RedBeanPHP\RedException: Identifier does not conform to RedBeanPHP security policies.
}

Congrats for PeachPie, it's an incredible tool for us, PHP programmers out there!

luizzaiats avatar Mar 29 '23 11:03 luizzaiats

you can simplify a few calls there, if you reference the PHP project from your C# project, i.e.: ctx.Call("R::setup", "sqlite:./dbfile.db"); -> R.setup(ctx, "sqlite:./dbfile.db");

and

dynamic _user = ctx.Call("R::dispense", "user");
_user.Object.__set("username", "luiz.zaiats");

->

var user = R.dispense(ctx, "user");
user.__set("username", "luiz.zaiats");

and

RedBeanPHP.OODBBean v = kv.Value.Object as RedBeanPHP.OODBBean -> var v = kv.Value.Cast<RedBeanPHP.OODBBean>()


anyways; if you have the full stack trace of the "Unhandled exception", we can do something about it

jakubmisek avatar Apr 29 '23 15:04 jakubmisek