【问题标题】:How to make a final variable in PHP?如何在 PHP 中创建最终变量?
【发布时间】:2017-05-13 21:10:28
【问题描述】:

我找不到,或者我想错了,但是我需要创建一个无法更改的变量,例如只读,例如:

final $finalVar = 'extremely secret number'; // don't change

$finalVar = 'hacked...'; // THROW I GIANT BIG ERROR HERE !

【问题讨论】:

  • 使用常量。
  • PHP 手册说明:属性不能声明为final,只有类和方法可以声明为final。 php.net/manual/en/language.oop5.final.php
  • @bishop 正确。对于他们的特定用例,一个常数是有效的。但如果他们着眼于更广泛的范围,那么需要注意这一点。
  • 基本上,你需要一个常量,但你想用美元符号编写代码——这就是它的归结。解决方案非常简单——不要再写美元符号,而是使用为特定目的而存在的语言结构。

标签: php final php-7


【解决方案1】:

除了常量(如 cmets 中所述)之外,我能想到的唯一方法是使用带有 private 变量的父子关系

class ParentC {
    private $var = 'bob';
}

class ChildC extends ParentC {
    public function setVar() {
         // Fatal error: Uncaught Error: Cannot access private property ParentC::$var
         echo parent::$var; 
    }
}

请注意,a hacky way around that 使用反射类。但是,在大多数情况下,您不能触摸子类中的 private 父变量

【讨论】:

  • 子类不能改变变量,也不能读取。
  • @Andrea 是的,但你可以创建一个 getter 方法或重载来解决这个问题
【解决方案2】:

如果要创建不想更改的变量,可以使用常量:

class MyClass {

   const VERSION = '2.1'; // This constant can be view outside the class,
                          // but its value can't be changed even in this class

   function myMethod () {
       echo self::VERSION; // Inside class
   }

}

或课外:

echo MyClass::VERSION;

功能方法:

define ('VERSION', '2.1');

echo VERSION;

【讨论】:

    【解决方案3】:

    虽然至少从 2012 年开始就有talk 的只读变量,甚至还有RFC 提出对象,但语言中不存在支持。

    实现只读变量(或只读变量的集合,对于某些配置值可能很重要)的一种方法是使用中介容器:

    class Readonly {
        public function __construct(...$vars) {
            $this->vars;
        }
    
        public function __set($var, $value) {
            if (array_key_exists($var, $this->vars)) {
                throw new \LogicException("Variable $var is read-only");
            } else {
                $this->vars[$var] = $value;
            }
        }
    
        public function __get($var) {
            return array_key_exists($var, $this->vars) ? $this->vars[$var] : null;
        }
    
        protected $vars = [];
    }
    

    这允许您创建只读变量的容器:

    $config = new Readonly('apikey');
    
    $config->apikey = 'A01AB020'; // this works, first time set
    echo $config->apikey;
    
    $config->apikey = '00000000'; // boom! it's "final"
    

    【讨论】:

    • 我想知道,如果实际解决方案是使用常量,为什么要这么长的答案?这里没有真正的问题,OP 只是不“想要”编写没有美元符号的代码。这似乎完全是过度杀伤IMO,问题出在椅子上,而不是电脑上。 OP 应该学习使用该语言,如果他没有明确的理由不想使用为特定目的提供的构造,则不要屈从于他的意愿。我没有对此投票,但我认为这是不正确的,因为它会误导未来的访问者。
    • @Mjh 常量只能是标量或数组(通过 5.6+ 中的 const 或 7.0+ 中的 define)。常量会污染全局命名空间。 const 是编译时的,必须在顶级范围内声明:不在函数、循环或 try/catch 中。 const 不能从变量初始化,如果 OP 从配置文件中读取,这可能很重要。 (define 可以,但是我们在
    • @bishop 可以定义类级常量。实际的解决方案是使用常量。无论您是通过全局范围还是类别来管理它们 - 由您决定。没有必要避免常量。如果某些东西是不可变的,那么它就不是变量。如果需要保存标量以外的其他内容,那么使用 IoC 和您演示的技术是可行的方法。总有适合这项工作的工具。
    【解决方案4】:

    使用常量:

    defined('VARIABLE')  OR define('VARIABLE', 'value');
    

    文档:definedefined

    【讨论】:

      【解决方案5】:

      使用PHP 8.1,您现在可以将变量声明为只读:

      class MyClass{
          public readonly string $prop;
       
          public function __construct(string $val) {
              // Can be intialized only once.
              $this->prop = $val;
          }
      }
      
      $myclass = new MyClass('Foo');
      $myclass->prop; // Read the property
      $myclass->prop = 'Bar'; // Error: Cannot modify readonly property
      

      请注意,您只能将只读应用于类型化属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-04
        • 2016-03-19
        • 2013-06-12
        • 1970-01-01
        • 2016-02-29
        • 2022-07-31
        • 1970-01-01
        • 2011-09-15
        相关资源
        最近更新 更多