5

I can't find out, or maybe I am thinking wrongly but I need to make a variable that can't be changed, like read-only, something like :

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

$finalVar = 'hacked...'; // THROW I GIANT BIG ERROR HERE !
vdegenne
  • 12,272
  • 14
  • 80
  • 106
  • 11
    Use a constant. – John Conde Dec 29 '16 at 14:17
  • 1
    https://secure.php.net/manual/en/language.constants.php – aynber Dec 29 '16 at 14:17
  • yeah I thought about constant but can't I be using it with the dollar ? – vdegenne Dec 29 '16 at 14:18
  • @ballangddang : no, constants in PHP do not start with a dollar sign, by convention they are generally uppercase and seperated with underscore (ex. `const MY_COOL_CONSTANT = 1`) but that's simply convention. – SolarBear Dec 29 '16 at 14:20
  • 2
    PHP manual note: Properties cannot be declared final, only classes and methods may be declared as final. http://php.net/manual/en/language.oop5.final.php – LugiHaue Dec 29 '16 at 14:23
  • A variable that cannot be changed isn't a variable, hence the name. – pbond Dec 29 '16 at 14:40
  • @JohnConde "use a constant" with the caveat that only scalars and arrays may be declared constant in that way. – bishop Dec 29 '16 at 14:42
  • 1
    @bishop Correct. For their specific use case a constant works. But if they are looking at a broader scope then this caveat is important to note. – John Conde Dec 29 '16 at 14:49
  • 3
    Basically, you need a constant, but you want to write code with dollar sign - this is what it boils down to. Solution is quite simple - stop wanting to write dollar sign and use language constructs that are there for your specific purposes. – Mjh Dec 29 '16 at 15:00
  • @Mjh I haven't used my account in ages but had to log in. Your answer is not correct at all and hopefully you know that by now (it's been 7 years after all). – StackOverflowed Mar 22 '23 at 20:21

5 Answers5

2

Aside from constants (as mentioned in comments), the only way I can think of to do this is to use a parent-child relationship with a private variable

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; 
    }
}

Note that there's a hacky way around that using the Reflection class. But, for the most part, you can't touch a private parent variable from a child class

Community
  • 1
  • 1
Machavity
  • 30,841
  • 27
  • 92
  • 100
2

You can use constants if you want to create variables which you don't want to be changed:

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
   }

}

or outside the class:

echo MyClass::VERSION;

Functional approach:

define ('VERSION', '2.1');

echo VERSION;
Acuna
  • 1,741
  • 17
  • 20
1

While there has been talk of read-only variables since at least 2012, with even an RFC proposing it on objects, the support does not exist in the language.

One way to achieve a read-only variable (or a collection of read-only variables, as might be important with certain configuration values) is with a mediating container:

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 = [];
}

Which allows you to create a container of read-only variables:

$config = new Readonly('apikey');

$config->apikey = 'A01AB020'; // this works, first time set
echo $config->apikey;

$config->apikey = '00000000'; // boom! it's "final"
bishop
  • 37,830
  • 11
  • 104
  • 139
  • I wonder, why such a long answer if the actual solution is to use constants? There's no real problem here, OP just doesn't "want" to write code without dollar sign. This seems like a total overkill IMO, the problem is in chair, not in computer. OP should learn to use the language, not to bend it to his will if he has no clear reason why he doesn't want to use constructs provided for specific purposes. I didn't vote on this, but I believe this is incorrect because it will mislead future visitors. – Mjh Dec 29 '16 at 14:58
  • 1
    @Mjh Constants can only be scalar or array (via `const` in 5.6+, or `define` in 7.0+). Constants pollute the global namespace. `const` is compile-time and must be declared at the top-level scope: not in functions, loops, or try/catch. `const` cannot be initialized from a variable, which may be important if the OP is reading from a config file. (`define` can, but then we've got the no-array problem in < 7, plus the namespacing and global pollution problems.) In short, I think it's a bit presumptive to state outright that "the actual solution is to use constants". – bishop Dec 29 '16 at 15:09
  • 1
    @bishop one can define class-level constants. The actual solution is to use constants. Whether you manage them through global scope or class - up to you. There exists no need to avoid constants. If something is immutable, it's not a variable. If one needs to save something else than a scalar then using IoC and technique demonstrated by you is the way to go. There's always the right tool for the job. – Mjh Dec 29 '16 at 15:35
1

With PHP 8.1 you can now declare a variable as readonly :

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

Note that you can only apply readonly to typed properties.

grunk
  • 14,718
  • 15
  • 67
  • 108
0

Use constant:

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

Documentation: define defined

Blaztix
  • 1,223
  • 1
  • 19
  • 28