2021/11/24/things you can't do in PHP
Example 1: my bad
This is where I started -- and admittedly there was already a problem in that I'm use
ing 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>