使抽象 class 方法只能从子 classes 公开访问
Make abstract class method only publicly accessible from child classes
首先,我们谈论的是 PHP 7.4.10,但任何通用英特尔都值得赞赏!
问题总结:我想在抽象 class 中定义一个静态方法,这样只能从子 classes 扩展抽象 class 中公开调用该方法 class 但不是来自摘要 class 本身。抱歉,如果我在这里太基础了,但我实际上已经搜索了几个小时来寻找答案,甚至找不到关于该主题的任何讨论。
让我们考虑以下示例(注释中的解释)。我希望能够调用 Apple::printName()
和 Pear::printName()
但不能调用 Fruit::printName()
.
abstract class Fruit
{
/*
* Oblige every child class to define a string name, nothing unusual
*/
protected abstract static function name() : string;
/*
* The problem is with the access modifier of this method here
***
* If it is public, everything is fine with Apple::printName() and Pear::printName(),
* but one can call Fruit::printName() from outside,
* resulting in PHP Error: Cannot call abstract method Fruit::name()
* this is still sort of okay, since an error will be thrown anyway,
* but I don't want the runtime to even enter the method's body
* I'd like to get an access restriction error.
***
* If it is protected, then we automatically can't call Apple::printName nor Pear::printName()
***
* So, is there a way to define the parent static method only publicly accessible from child classes without copying code?
*/
public static function printName()
{
return "My name is: " . static::name();
}
}
class Apple extends Fruit
{
protected static function name() : string
{
return "apple";
}
}
class Pear extends Fruit
{
protected static function name() : string
{
return "pear";
}
}
echo Apple::printName(); //prints "My name is: apple"
echo Pear::printName(); //prints "My name is: pear"
echo Fruit::printName(); //PHP Error: Cannot call abstract method Fruit::name() at line...
对于如何实现所需行为的任何替代方法,我也持开放态度。
public static function printName() {}
这是具体方法的定义。人们可能会认为调用此方法是可以的,因为它是非抽象 public 方法。那么,为什么 Fruit
没有对它做任何事情呢?
所以一个解决方案是定义一个 trait
和 use
它只在那些实际上 需要 的里面?
trait Printer {
public static function printName()
{
return "My name is: " . static::name();
}
}
abstract class Fruit
{
protected abstract static function name() : string;
}
class Apple extends Fruit
{
use Printer;
protected static function name() : string
{
return "apple";
}
}
class Pear extends Fruit
{
use Printer;
protected static function name() : string
{
return "pear";
}
}
但是,如果您的 Fruit
只是 child 类 的定义,就像您在评论中提到的那样,您恰好有 PHP 8 :) 那么也许就不要让 printName
静态
public function printName()
{
return "My name is: " . static::name();
}
和
$a = new Apple();
$p = new Pear();
echo $a->printName();
echo $p->printName();
现在 echo Fruit::printName();
将为您提供您一直在寻找的致命错误。
Fatal error: Uncaught Error: Non-static method Fruit::printName()
cannot be called statically
您可以检查您的实例是否是子类,如果不是则退出
abstract class A1 {
public static function childrenOnly() {
return is_subclass_of(new static, 'A1');
}
}
class A2 extends A1 {
}
Al::childrenOnly(); // errors out
A2::childrenOnly(); // true
所以在阅读了所有的答案后,我想出了一个 workaround-ish 解决方案,最终决定赞成 @chilliNUT 的建议。我最终按如下方式进行:
abstract class Fruit
{
protected abstract static function name() : string;
/*
* Basically, if you call the default method from any child (not necessarily a direct child) class, no problems,
* but if you call it directly from the baseclass, you get the somewhat acceptable exception :)
*/
public static function printName()
{
if(!is_subclass_of(static::class, self::class))
{
throw new \BadMethodCallException("Can't call base Fruit class methods directly!");
}
return "My name is: " . static::name();
}
}
//those are abstract now, just to match the intention of them being utility singletons
abstract class Apple extends Fruit
{
protected static function name() : string
{
return "apple";
}
}
abstract class Pear extends Fruit
{
protected static function name() : string
{
return "pear";
}
}
无论如何,从@Rain的回答我可以看出为什么这往往是一种不好的做法,实际上不是继续发展的最佳方向,所以我会考虑我要实现的目标的不同策略。终于满足了我的好奇心!感谢大家的参与!
首先,我们谈论的是 PHP 7.4.10,但任何通用英特尔都值得赞赏!
问题总结:我想在抽象 class 中定义一个静态方法,这样只能从子 classes 扩展抽象 class 中公开调用该方法 class 但不是来自摘要 class 本身。抱歉,如果我在这里太基础了,但我实际上已经搜索了几个小时来寻找答案,甚至找不到关于该主题的任何讨论。
让我们考虑以下示例(注释中的解释)。我希望能够调用 Apple::printName()
和 Pear::printName()
但不能调用 Fruit::printName()
.
abstract class Fruit
{
/*
* Oblige every child class to define a string name, nothing unusual
*/
protected abstract static function name() : string;
/*
* The problem is with the access modifier of this method here
***
* If it is public, everything is fine with Apple::printName() and Pear::printName(),
* but one can call Fruit::printName() from outside,
* resulting in PHP Error: Cannot call abstract method Fruit::name()
* this is still sort of okay, since an error will be thrown anyway,
* but I don't want the runtime to even enter the method's body
* I'd like to get an access restriction error.
***
* If it is protected, then we automatically can't call Apple::printName nor Pear::printName()
***
* So, is there a way to define the parent static method only publicly accessible from child classes without copying code?
*/
public static function printName()
{
return "My name is: " . static::name();
}
}
class Apple extends Fruit
{
protected static function name() : string
{
return "apple";
}
}
class Pear extends Fruit
{
protected static function name() : string
{
return "pear";
}
}
echo Apple::printName(); //prints "My name is: apple"
echo Pear::printName(); //prints "My name is: pear"
echo Fruit::printName(); //PHP Error: Cannot call abstract method Fruit::name() at line...
对于如何实现所需行为的任何替代方法,我也持开放态度。
public static function printName() {}
这是具体方法的定义。人们可能会认为调用此方法是可以的,因为它是非抽象 public 方法。那么,为什么 Fruit
没有对它做任何事情呢?
所以一个解决方案是定义一个 trait
和 use
它只在那些实际上 需要 的里面?
trait Printer {
public static function printName()
{
return "My name is: " . static::name();
}
}
abstract class Fruit
{
protected abstract static function name() : string;
}
class Apple extends Fruit
{
use Printer;
protected static function name() : string
{
return "apple";
}
}
class Pear extends Fruit
{
use Printer;
protected static function name() : string
{
return "pear";
}
}
但是,如果您的 Fruit
只是 child 类 的定义,就像您在评论中提到的那样,您恰好有 PHP 8 :) 那么也许就不要让 printName
静态
public function printName()
{
return "My name is: " . static::name();
}
和
$a = new Apple();
$p = new Pear();
echo $a->printName();
echo $p->printName();
现在 echo Fruit::printName();
将为您提供您一直在寻找的致命错误。
Fatal error: Uncaught Error: Non-static method Fruit::printName() cannot be called statically
您可以检查您的实例是否是子类,如果不是则退出
abstract class A1 {
public static function childrenOnly() {
return is_subclass_of(new static, 'A1');
}
}
class A2 extends A1 {
}
Al::childrenOnly(); // errors out
A2::childrenOnly(); // true
所以在阅读了所有的答案后,我想出了一个 workaround-ish 解决方案,最终决定赞成 @chilliNUT 的建议。我最终按如下方式进行:
abstract class Fruit
{
protected abstract static function name() : string;
/*
* Basically, if you call the default method from any child (not necessarily a direct child) class, no problems,
* but if you call it directly from the baseclass, you get the somewhat acceptable exception :)
*/
public static function printName()
{
if(!is_subclass_of(static::class, self::class))
{
throw new \BadMethodCallException("Can't call base Fruit class methods directly!");
}
return "My name is: " . static::name();
}
}
//those are abstract now, just to match the intention of them being utility singletons
abstract class Apple extends Fruit
{
protected static function name() : string
{
return "apple";
}
}
abstract class Pear extends Fruit
{
protected static function name() : string
{
return "pear";
}
}
无论如何,从@Rain的回答我可以看出为什么这往往是一种不好的做法,实际上不是继续发展的最佳方向,所以我会考虑我要实现的目标的不同策略。终于满足了我的好奇心!感谢大家的参与!