2021/11/24/things you can't do in PHP

From Woozle Writes Code
Revision as of 22:58, 24 November 2021 by Woozle (talk | contribs) (Created page with "{{nav/codeblog}} ==Example 1: my bad== This is where I started -- and admittedly there was already a problem in that I'm <code>use</code>ing '''taScalarAccess''' twice in '''c...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
Codeblog

Example 1: my bad

This is where I started -- and admittedly there was already a problem in that I'm useing taScalarAccess twice in cScalarReadOnly (once each via cScalarLocal and taReadOnlyScalar). The idea, though, was to override the SetIt() and ClearIt() methods in whatever class was using taReadOnlyScalar. Those methods being implemented in cScalarLocal, the use of the taReadOnlyScalar trait was intended to rename those methods with a "_" prefix and call them conditionally from the replacement methods.

trait taScalarAccess {
    abstract public function SetIt(mixed $v);
    abstract public function GetIt() : mixed;
    abstract public function HasIt() : bool;
    abstract public function ClearIt();
}
trait tScalarLocal {
    use taScalarAccess;
    public function GetIt() : mixed {}
    public function HasIt() : bool {}
    public function SetIt(mixed $v) {}
    public function ClearIt() {}
}
trait taReadOnlyScalar {
    use taScalarAccess {
      taScalarAccess::SetIt as protected _SetIt;
      taScalarAccess::ClearIt as protected _ClearIt;
      }
    public function SetIt(mixed $v) { if ($something) { $this->_SetIt($v); } }
    public function ClearIt() { if ($something) { $this->_ClearIt(); } }
}

class cScalarLocal {
    use taScalarAccess;
    use tScalarLocal;
}
class cScalarReadOnly extends cScalarLocal {
    use tScalarLocal;
    use taReadOnlyScalar;
}

Result

PHP Fatal error: Trait method SetIt has not been applied, because there are collisions with other trait methods on cScalarReadOnly in /home/htnet/site/git/ferreteria/base/tests/php2.php on line 28

Example 2: decouple the conflicting traits

First, I tried moving use taScalarAccess out of tScalarLocal, even though I wanted the latter to descend from the former because of a method implemented in the former (not shown). Classes that use tScalarLocal would also need to explicitly use taScalarAccess in order to get that functionality.

trait taScalarAccess {
    abstract public function HasIt() : bool;
    abstract public function GetIt() : mixed;
    abstract public function SetIt(mixed $v);
    abstract public function ClearIt();
}
trait tScalarLocal {
    public function HasIt() : bool {}
    public function GetIt() : mixed {}
    public function SetIt(mixed $v) {}
    public function ClearIt() {}
}
trait taReadOnlyScalar {
    use taScalarAccess {
      taScalarAccess::SetIt as protected _SetIt;
      taScalarAccess::ClearIt as protected _ClearIt;
      }
    public function SetIt(mixed $v) { if ($something) { $this->_SetIt($v); } }
    public function ClearIt() { if ($something) { $this->_ClearIt(); } }
}

class cScalarLocal {
    use taScalarAccess;
    use tScalarLocal;
}
class cScalarReadOnly extends cScalarLocal {
    use tScalarLocal;
    use taReadOnlyScalar;
}

Result

PHP Fatal error: Trait method SetIt has not been applied, because there are collisions with other trait methods on cScalarReadOnly in /home/htnet/site/git/ferreteria/base/tests/php2.php on line 27

i.e. that didn't fix the problem.

Example 3: interface

Next, I tried moving the abstract functions from taScalarAccess into an interface, to avoid the collision. (Had this worked, it would have been nice if traits could implement interfaces, but it didn't so the point is moot as far as this issue goes.)

interface ifScalarAccess {
    function HasIt() : bool;
    function GetIt() : mixed;
    function SetIt(mixed $v);
    function ClearIt();
}
trait taScalarAccess {}
trait tScalarLocal {
    public function HasIt() : bool {}
    public function GetIt() : mixed {}
    public function SetIt(mixed $v) {}
    public function ClearIt() {}
}
trait taReadOnlyScalar {
    use taScalarAccess {
      taScalarAccess::SetIt as protected _SetIt;
      taScalarAccess::ClearIt as protected _ClearIt;
      } //*/
    public function SetIt(mixed $v) { if ($something) { $this->_SetIt($v); } }
    public function ClearIt() { if ($something) { $this->_ClearIt(); } }
}

class cScalarLocal implements ifScalarAccess {
    use taScalarAccess;
    use tScalarLocal;
}
class cScalarReadOnly extends cScalarLocal {
    use tScalarLocal;
    use taReadOnlyScalar;
}

Result

PHP Fatal error: An alias was defined for taScalarAccess::SetIt but this method does not exist in /home/htnet/site/git/ferreteria/base/tests/php2.php on line 15<?blockquote>