PHP wishlist

From Woozle Writes Code
Jump to navigation Jump to search

These are features I wish PHP would add. As far as I know, they are not available on PHP 8, though I have only used up through 7.4 as of this writing.

Trait wishlist

  • /combine traits and interfaces: they're basically subsets of the same thing.
  • Where class A uses trait B, where both define function C(), A::C() should be able to call parent::C() to refer to B::C() if it exists.
  • You should be able to define function parameters as traits, the same way you can do for classes or interfaces. (This would also be solved by combining traits and interfaces.)
  • /trait implements: Traits should be able to implement one or more interfaces, the way classes can.
  • When using a trait, it should be possible to add a prefix to all of the member variables and functions -- so that you could use a trait in multiple ways.
    • Example: a trait which is a wrapper for a member-variable object -- if you needed two such objects with different names, you wouldn't have to re-write the access shortcuts for each one.
    • This nonexistent feature, as far as I know, would be the only reason to keep traits and interfaces as separate things (and there's probably a way to work it in if they were combined).

first keyword

There needs to be a companion to the final keyword in #PHP.

Background: The "final" keyword indicates that a method cannot be overridden in a child class.

Wish: There needs to be a "first" keyword to prevent accidentally creating a method ancestor which might get completely bypassed because a descendant doesn't call parent::[method] because it doesn't expect one to exist.

Either that, or a way to allow calls to parent::[method]() even when there's no method ancestor.

The virtual fx chaining idea below would also address this problem, though I'm not sure it's as good a solution.

post: 2021-05-31 @TootCat

Virtual fx chaining

Current Behavior

If you have class B which extends class A and they both define function C(), and you call C() in an object of class B, you just get B::C(). The class-structure may be designed, however, in such a way that it's necessary to also run code in the parent class, where B is adding functionality rather than replacing it.

The standard way of accomplishing this is for B::C() to call parent::C() at some point. However it can often be difficult to know whether there is a parent C(), especially where B isn't immediately descended from A (e.g. B extends A3 which extends A2 which extends A1 which extends A) or where there are traits being introduced at any point.

The best way I've found for dealing with that is for the class structure to define a stub C() which does nothing (function C() {}), and to have a rule that all other implementations of C() must call parent::C(). This, however, requires remembering the rule, and also seems a little wasteful in that there may be a lot of calls to an empty function that is really just a placeholder.

Proposal

To fix this, I propose a set of keywords for use in function definitions. This keyword will set the default behavior of offspring functions, and overrides any default if used in offspring functions. Using A, B, and C() as above, this is what will happen if C() is called in an object of class B:

  • replace (or instead): B::C() replaces A::C(), so only B::C() will execute.
    • This is the current behavior.
  • before: A::C() will execute, then B::C().
  • after: B::C() will execute, followed automatically by A::C().