2021/05/28/a kluge using abstract methods: Difference between revisions

From Woozle Writes Code
Jump to navigation Jump to search
(Created page with "{{box/nav/log}} category:post category:ferreteria I don't know if I'll end up using this technique or not, but I thought I'd make a note of it because of the underlyin...")
 
mNo edit summary
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{box/nav/log}}
{{nav/codeblog}}
[[category:post]]
[[category:post]]
[[category:ferreteria]]
[[category:PHP 7.4]]
I don't know if I'll end up using this technique or not, but I thought I'd make a note of it because of the underlying problem it illustrates.
I don't know if I'll end up using this technique or not, but I thought I'd make a note of it because of the underlying problem it illustrates.


* I have a number of traits which need to be initialized somehow.
* I have a number of [https://php.net/trait traits] which need to be initialized somehow.
* It turns out to be a bad idea to define constructors inside traits, because the different classes that use those traits may have different constructor arguments.
* It turns out to be a bad idea to define constructors inside traits, because the different classes that use those traits may have different constructor arguments.
** In other words, there's no clean way to have a trait call the constructor of a class that uses it, unless you carefully restrict what classes can use it...
** In other words, there's no clean way to have a trait call the constructor of a class that uses it, unless you carefully restrict what classes can use it...
Line 12: Line 12:


The solution I'm trying is to just define an abstract method named "Call_''[name_of_initialization_method]''". Whatever host does the calling simply defines this method with no code, to signal that the call has happened. This serves as nothing more than a reminder to the coder that a thing needs to be done when using a given trait.
The solution I'm trying is to just define an abstract method named "Call_''[name_of_initialization_method]''". Whatever host does the calling simply defines this method with no code, to signal that the call has happened. This serves as nothing more than a reminder to the coder that a thing needs to be done when using a given trait.
==Example==
<syntaxhighlight lang=php>
/*::::
  HOSTING: Host must call CreatePortBank() before calling PortBank().
*/
trait tMaker {
    use tUser;
    abstract protected function Call_CreatePortbank();  // a reminder
    protected function CreatePortBank() {
        $sClass = $this->PortBankClass();
        $os = $this->Space();
        $op = $os->MakePiece($this->PortBankPieceName());
        $of = new $sClass($os);
        $op->SetIt($of);
    }
    abstract protected function PortBankClass() : string;
}
</syntaxhighlight>

Latest revision as of 00:07, 2 July 2022

Codeblog

I don't know if I'll end up using this technique or not, but I thought I'd make a note of it because of the underlying problem it illustrates.

  • I have a number of traits which need to be initialized somehow.
  • It turns out to be a bad idea to define constructors inside traits, because the different classes that use those traits may have different constructor arguments.
    • In other words, there's no clean way to have a trait call the constructor of a class that uses it, unless you carefully restrict what classes can use it...
      • ...and even if that were desirable (which it is in some circumstances), there's no way to enforce it.
  • I had resorted to putting notes in the trait documentation -- like "HOSTING: host must call [name_of_trait_initialization_method]"...
    • ...but when a trait is several layers deep in other traits (which happens a lot with the method/routing pattern I use), this can be easy to overlook.

The solution I'm trying is to just define an abstract method named "Call_[name_of_initialization_method]". Whatever host does the calling simply defines this method with no code, to signal that the call has happened. This serves as nothing more than a reminder to the coder that a thing needs to be done when using a given trait.

Example

/*::::
  HOSTING: Host must call CreatePortBank() before calling PortBank().
*/
trait tMaker {
    use tUser;
    abstract protected function Call_CreatePortbank();  // a reminder
    protected function CreatePortBank() {
        $sClass = $this->PortBankClass();
        $os = $this->Space();
        $op = $os->MakePiece($this->PortBankPieceName());
        $of = new $sClass($os);
        $op->SetIt($of);
    }
    abstract protected function PortBankClass() : string;
}