peachpiecompiler / peachpie

PeachPie - the PHP compiler and runtime for .NET and .NET Core
https://www.peachpie.io
Apache License 2.0
2.38k stars 203 forks source link

trait support #102

Closed jakubmisek closed 6 years ago

jakubmisek commented 7 years ago

Implement support for using traits. See http://php.net/manual/en/language.oop5.traits.php for specs.

Used trait should be instantiated inside the class as a private "compiler-generated" object. Its members exposed by the class as generated methods that will call members on the trait instance.

trait class

trait T {
  function t_foo() {}
}

... compiles into IL equivalent to following:

[PhpTrait] public sealed class T<TSelf> { // TSelf is type of the trait owner, resolves `self`, static fields and optimizes callsites
  readonly TSelf <this>; // actual instance of class that uses the trait

  public PhpValue t_foo() { return PhpValue.Null; }
}

using the trait

class X {
  use T;
}

... compiles into IL equivalent to following:

public class X {
  private readonly T <>_t; // trait instance

  X(Context <ctx>) { this.<>_t = new T<X>(<ctx>, this); }
  public virtual PhpValue t_foo() { return this.<>_t.t_foo(); } // forwarding call to the trait instance
}
ztl8702 commented 7 years ago

+1 for this. Was trying to compile Drupal 8 using Peachpie and then realised that Drupal 8 uses PHP trait extensively.

hadi77ir commented 7 years ago

Isn't it possible to implement traits using interfaces?

jakubmisek commented 7 years ago

@hadi77ir traits have implementations and fields and can extend other classes. Even tho CLR allows interfaces with implementations I think it wouldn't be a good practice. Also this wouldn't allow trait members aliasing.

jakubmisek commented 6 years ago

preview of trait support implemented in https://github.com/peachpiecompiler/peachpie/commit/81bee0e1815b8f53f14b26442b1f336206908d6d

Xon commented 6 years ago

@jakubmisek php implements traits as basically copy & pasting a trait into a class's namespace. This means constants, fields and methods of the hosting class can be called by any trait method as if it was part of the trait.

Would the generated separate class implementation allow this?

jakubmisek commented 6 years ago

@Xon yes it works. Inside the trait method, members will be accessed dynamically.

Just my personal note: it is not a good practice to call something that is not there in design time. Compose class with instances of services instead of traits, or define abstract methods in the trait. Otherwise bad trait pushes developers to create an unmaintainable piece code.

Xon commented 6 years ago

It wouldn't be so bad if you could restrict a trait to being used to class implements a particular interface/abstract class.

But the php traits where added back int the php 5.4 days, and don't appear to have been touched spec-wise in the php 7.x language updates.

jakubmisek commented 6 years ago

Closing as implemented in order to run our test cases and PHP examples successfully.