Is it possible to prevent variables from being overwritten in PHP? I am making a system that has some reserved variables and I don't want them to be replaced with something else after a certain point. It is possible? If not, what can I do to approach something close to this?
Some of these vars are instantiated classes so I can't define them as constants.
Take a look at this question. Also the information about constants in the PHP manual may be helpful.
Yes, they're called constants.
If you cannot use them, assuming you're running the latest PHP version, you can use namespaces, using namespaces, you can have 2 variables of the same name, on different namespaces. So that you don't have collisions.
The best you can do (that I am aware of) in this case is make them private variables inside the class. Then you have to use getters and setters to assign the values, or a construct. That way, someone else's code is less likely to collide with yours.
It's impossible to find out how it is the easiest in your situations, as there is no code available at all, but on of the better options would probably be is
hide them in a class as private member vars.
expose them through getters.
If needed, make them static
Maybe you can implement something like frozen state, and if class is frozen, can't be modified:
class Test
{
private $variable;
private $frozen = false;
public function freeze() {
$this->frozen = true;
}
public function setVariable($value) {
if ($this->frozen)
throw new Exception("...");
$this->variable = $value;
}
}
Related
I'm new to the OOP paradigm, so there's probably a simple explanation for this question...
Do you always need to declare public object-wide variables in a class? For example:
<?php
class TestClass
{
var $declaredVar;
function __construct()
{
$this->declaredVar = "I am a declared variable.";
$this->undeclaredVar = "I wasn't declared, but I still work.";
}
function display()
{
echo $this->declaredVar . "<br />";
echo $this->undeclaredVar;
echo "<br /><br />";
}
}
$test = new TestClass;
$test->display();
$test->declaredVar = "The declared variable was changed.";
$test->undeclaredVar = "The undeclared variable was changed.";
$test->display();
?>
In this code, even though $declaredVar is the only declared variable, $undeclaredVar is just as accessible and useable--it seems to act as if I had declared it as public.
If undeclared class variables are always accessible like that, what's the point of declaring them all up front?
That variable isn't uninitialized, it's just undeclared.
Declaring variables in a class definition is a point of style for readability.
Plus you can set accessibility (private or public).
Anyway, declaring variables explicitly has nothing to do with OOP, it's programming-language-specific. In Java you can't do that because variables must be declared explicitly.
If you declare a member inside the class you can set its accessibility e.g
private $varname;
You should always declare your member variables and specify their accessibility within your classes. I like to put this information at the end of the class after my functions.
You should define them as soon as you have enough information to do so. Possibly in the constructor or via setter functions.
It is important to do this because it makes life much easier for people working with your code. They don't have to guess where different properties are coming from or why they're there. Also, most (if not all) IDEs will not pick up on class variables unless you've declared them somewhere. Code completion/hints are one of the many benefits of IDEs and without declaring your variables, you will render that functionality useless.
General OOP paradigm of encapsulation says you should not expose your inner state variables out side that means they should be private, that allows you to change an implementation of your class without need to change the code where you make use of it. It's better practice to initialize variables via constructors and getters and setters method of the class.
In general variables should be initialized as soon as you have enough info to do it properly.
If a class variable needs certain info to be sensibly initialized then that info should be passed to the constructor.
Using PHP's syntax to implicitly declare variables at the point of definition is, IMHO a surefire way to introduce bugs - if your class needs a variable then declare it, and use all of the information hiding that OOP affords you.
As Federico Culloca said "That variable isn't uninitialized, it's just undeclared". Also you didn't define any access modifiers for them so that they behaving like public modifier applied to them.
You may already have known, PHP is a loosely typed language. But a programmer should always follow the best practices and define access modifiers manually. It increases code readability.
You can use private modifier for class level variables and provide accessor and mutator methods (Getters and Setters) for them when needed.
TLDR: Only Define What Isn't in The Default/Public
To define or not define global variables within class scope — ultimately, it is a design decision that should be taken to improve code readability, and nothing more. Personally, I don't "define all of these," and I use the default scope of public (Source: PHP.net -> Visibility). I do that until I actually need to change any of them for a particular need.
The Basic Objection
"But shouldn't that be set so we can define public and private as needed?" : If you need to set a global variable's status, then set it. Until you set it, it is public. So, set it when you need it. Don't write code that does nothing with the hope that one day in the future you'll thank yourself -- odds are you may need to completely revamp everything your old self did. And what if you have hundreds of variables all set to the same default instance? How does that help anyone?
Why Avoid Hardcoding the Accessibility Value on Attributes?
At some point, we will be able to configure the default, and then all that code that hard-coded this class accessibility, or that class accessibility, will need to be reprogrammed. In general, hard-coding is bad, and the large amounts of typing/copying-pasting associated with class attribute access definitions is just not worth the result. Use the default.
It's Really All About Style
If all your class variables public and the extra global definitions (100's of them maybe) doesn't help you, then dump them. If they give structure to your code, though, then keep them. It's something done to help the coder, not the compiler.
Which would you rather have to fix?
This?
class basicscript extends baseformat {
public function __construct($args) {
$this->startUp($args);
return $this;
}
}
Or this?
class basicscript extends baseformat {
public $desired_script;
public $desired_action;
public $object_code;
public $object_parent;
public $object_list;
public $script_location;
public $script_name;
public $script_file;
public $script_extension;
public $script_format;
public $script_format_lower;
public $script_args;
public $authentication_object;
public $cleanser_object;
public $query_object;
public $db_access_object;
public $domain_object;
public $language_object;
public $dictionary;
public $time;
public $cookie;
public $formats_object;
public $version_object;
public $redirect_object;
public function __construct($args) {
$this->startUp($args);
return $this;
}
}
Can I define a class constant inside the class constructor function ?
(based on certain conditions)
That goes against the idea of class constants - they should not be dependent on a specific instance. You should use a variable instead.
However, if you insist on doing this, are very adventurous and can install PHP extensions, you can have a look at the runkit extension that allows to modify classes and their constants at runtime. See this doc: http://www.php.net/manual/en/function.runkit-constant-add.php
I don't think you can.
It wouldn't make sense, either - a class constant can be used in a static context, where there is no constructor in the first place.
You'll have to use a variable instead - that's what they're there for.
Try look here:
http://php.net/manual/en/language.oop5.constants.php
http://php.net/manual/en/language.oop5.static.php
Hope this helps.
As far as standard instance constructors go, there is no way to do this, and as others have pointed out, it wouldn't make sense. These constructors are called per created object instance, at the point they are created. There is no guarantee this constructor would get called before some code tried to access the constant. It also doesn't make sense in that the code would get called over and over again each time a new instance was constructed, whereas a const should only get set once.
It would be nice if PHP either offered some kind of static constructor that let you set the value one time for uninitialized constants, or allowed more types of expressions when defining constants. But these are not currently features of PHP. In 2015 an RFC was made that proposed adding static class constructors, but it is, at the time of me writing this answer, still in the draft status, and has not been modified since 2017.
I think the best alternative for now is to not use constants in this kind of scenario, and instead use static methods that return the value you want. This is very simple in that it only uses the PHP language features as is (not requiring any special extensions), these static methods can be called in the standard way, and you don't need to hack the autoloading process to call some kind of initializer function that sets static variables. The method might need to rely on private static variables in order to make sure the same instance is returned every time, if an object instance is being returned. You would need to write the implementation of this method to be constant like in the sense that it will always return the same thing, but takes advantage of being able to do things you can't do with a constant, like return on object instance or rely on complex expressions or function calls. Here is an example:
final class User
{
/** #var DefinitelyPositiveInt|null */ private static $usernameMaxLength;
public static function getUsernameMaxLengthConst(): DefinitelyPositiveInt
{
if ($usernameMaxLength === null) {
$usernameMaxLength = new DefinitelyPositiveInt(40);
}
return $usernameMaxLength;
}
}
$usernameInput.maxLength = User::getUsernameMaxLengthConst();
This is still not a perfect solution because it relies on the programmer to write these in a constant like way when that is desired (always returning the same value). Also, I don't like that the best place to document the fact that it is a const is in the method name, thus making it even longer to call. I also don't like that you now have to call it as a method instead of just accessing a property, which would be syntactically nicer.
This example is essentially an implementation of a singleton, but sometimes the purpose of a singleton is to be a constant rather than just a singleton. What I mean is, you might want the instance to always exist, and it might be an immutable type (none of the properties are public or mutable, only having methods that return new objects/values).
I am sorry to break it to you but it is not possible in vanilla PHP.
I am not very sure about frameworks or extensions but I am sure that it is not possible in vanilla PHP.
I recommend you to use variables instead.
You still can't, but maybe some of these (progressively weirder) ideas (just ideas, not true solutions) will work for you:
(1) You could use a private property, with a public getter method. The property cannot be modified outside the class, such as constants, but unfortunately it is accessed as a method, not as a constant, so the syntax is not the same.
class aClass{
private $const;
function __construct($const){
$this->const=$const;
}
function const(){
return $this->const;
}
}
$var1=new aClass(1);
echo $var1->const(); //Prints 1
(2) If you really want this value to be accessed as constant from outside, you can use define () inside the constructor. Unfortunately it doesn't get tied to the class or object name (as it do when you use const, using for example myClass::myConst). Furthermore, it only works if you create a single instance of the class. The second object you create is going to throw an error for redefining the constant, because is untied.
class otherClass{
function __construct($const){
define('_CONST',$const);
}
function const(){
return _CONST;
}
}
$var2=new otherClass('2');
echo $var2->const(); //Prints 2
echo _CONST; //Prints 2
#$var3=new aClass('3'); //Notice: Constant _CONST already defined
echo _CONST; //Still prints 2!
(3) Perhaps that last problem can be solved by giving variable names to the constants, related to the object to which they belong. This may be a bit weird... but maybe it works for someone.
class onemoreClass{
private $name;
function __construct($const,$name){
$this->name=$name;
$constname=$this->name."_CONST";
define($constname,$const);
}
function const(){
return constant($this->name.'_CONST');
}
}
$name='var4';
$$name=new onemoreClass(4,$name);
echo $var4->const(); //Prints 4
echo var4_CONST; //Prints 4
$name='var5';
$$name=new onemoreClass(5,$name);
echo $var5->const(); //Prints 5
echo var5_CONST; //Prints 5
I have a class that I am using all over the place in my code. It contains settings and other core functionality. Here's what I'm doing right now to use the class.
$settings = new Settings();
$settings->loadSettings();
Then, when I need to the code in some random function in another class, I do something like this:
function abc() {
global $settings;
$variable = $settings->a;
}
I'm sick and tired of randomly calling global $settings all over the place to pull in that settings object. I don't want to use the $_GLOBALS array (I don't know why, I just don't want to).
I'm thinking I want to switch to have a static class variable called $settings inside of settings. The code would look like this:
Settings::$settings = new Settings();
Settings::$settings->loadSettings();
Then, whenever I want to use it, I never have to worry about sucking it in via the global operator:
function abc() {
$variable = Settings::$settings->a;
}
Good idea or bad idea?
Well it's probably an improvement on globals, because it solves all the ugly scoping issues that globals cause. Getting rid of the global operator is generally a good thing! What you are doing is not dissimilar to the singleton pattern, though it's considerably simpler. (See the "Singleton" section at http://php.net/manual/en/language.oop5.patterns.php for more information on the pattern.) Your solution is almost certainly fine for your purposes.
On the other hand, there may be better ways of achieving the same thing that decouple your code more. That is to say, each class becomes more capable of being used in another project without significant recoding. One way to do this would be to "inject" the settings object into each class:
class ABC {
private $settings;
public function __construct($settings) {
$this->settings = $settings;
}
public function someMethod() {
$variable = $this->settings->a;
}
}
This would be more work, but may improve the re-usability of your code. You could then, for example, write a different settings class for every project but use the same ABC class.
This process, where you "inject" an object into another object that depends on it, is called dependency injection. There are other, more complex ways of doing this, including complex containers. See http://fabien.potencier.org/article/11/what-is-dependency-injection for an interesting set of tutorials on the subject. They're probably incidental to your current needs, but may help either now or in the future.
It seems you are looking for a Singleton. Basically the idea is to have a class which has a public static method getInstance() which returns an instance of the class itself. The first time you call the method, it stores the instance in a private property, and all later time it returns the stored instance. In this way, whenever you call Settings::getInstance(), you are guaranteed to have a copy of the same object. Then you can store settings in this object.
I've had a good read of the PHP specs on overloading, and most of the examples appear to be intended to simply allow defining of custom fields (similar to stdClass).
But what about the private fields defined in my class? How should these be retrieved/assigned? I could do a switch on possible values and act on certain values:
class A
{
private $name;
private $age;
public function __get( $var )
{
switch ( $var )
{
case 'name':
return $this->name;
break;
case 'age':
return $this->age+10; // just to do something different ;)
break;
default:
break;
}
}
}
Is this the best method, or is there another generally accepted best practice? (I don't know if it's possible to loop class variables inside a class, but regardless that's not appropriate in most situations since you don't want to return everything.)
I make extensive use of __get() and __set() AND I have my properties declared public. I wanted the best of both worlds, so my IDE could list public properties for me when I type the name of a class instance. How did I get the PHP interceptor methods to work, even though the properties are public and visible outside the class?unset() the properties I want __get() and __set() to be used for in the class __construct().Figuring this method out took a couple evenings of frustration :-)
This would effectively make them public, and usually this gains you nothing over simply using public properties (but you pay performance penalty and have to write more code, risk bugs).
Use that only if you have existing code that uses public property and you suddenly need getter/setter for it (like your example with age).
If you need to execute some code when property is read/written (e.g. make it read-only or lazily fetch from the database), then you should use normal getters/setters (getAge()/setAge()).
I don't see many people using them, but here is what I think.
For retrieving private variables, you probably want to give a list of defined variables that are able to be accessed by the outside. Then, check to see if the requested variable is in that array. If it is, allow it to be changed/gotten. If not, either error or return null.
Honestly, the implementations for this are really case-by-case. If you had a user class that you stored all the info in a single array, you could have $user->name be pulled from $user->account['name'], or something like that.
Also, in a more case-by-case, you could do some modification before giving them values, like hashing a password.
I have a very special case in which I need to call a protected method from outside a class. I am very conscious about what I do programmingwise, but I would not be entirely opposed to doing so in this one special case I have. In all other cases, I need to continue disallowing access to the internal method, and so I would like to keep the method protected.
What are some elegant ways to access a protected method outside of a class? So far, I've found this.
I suppose it may be possible create some kind of double-agent instance of the target class that would sneakily provide access to the internals...
In PHP you can do this using Reflections.
To invoke protected or private methods use the setAccessible() method
http://php.net/reflectionmethod.setaccessible (just set it to TRUE)
I would think that in this case, refactoring so you don't require this sort of thing is probably the most elegant way to go. In saying that one option is to use __call and within that parse debug_backtrace to see which class called the method. Then check a friends whitelst
class ProtectedClass {
// Friend list
private $friends = array('secret' => array('FriendClass'));
protected function secret($arg1, $arg2) {
// ...
}
public function __call($method, $args) {
$trace = debug_backtrace();
$class = $trace[1]['class'];
if(in_array($class, $this->friends[$method]))
return $this->$method($args[0], $args[1]);
throw new Exception();
}
}
I think I need a shower.
This is a little kludgy, but might be an option.
Add a child class for the sake of accessing your protected function
public class Child extends Parent {
public function protectedFunc() {
return parent::protectedFunc();
}
}
Then, instantiate an instance of Child instead of Parent where you need to call that function.
I'm just throwing this out there since I haven't programmed in PHP in two years. Could you just add a function to the class that calls the protected method like so?
$obj->publicFunc = create_function('$arg', 'return $this->protectedFunc($arg);');
Edit:
I think Tom's correct in looking at the documentation for create_function. It looks like the scope of $this will be "wrong" when you try to call it with this example.
It looks like traditional anonymous functions are supported since PHP 5.3.0 as well (and my first solution probably won't work), so I'd probably write it like this instead:
$obj->publicFunc = function($arg) {
return $this->protectedFunc($arg);
};
Since I think it looks a little cleaner (and your IDE of choice will highlight it better of course).
Ugh, I tried using Reflection to call the method but PHP won't allow you to do that either. It seems that you're going to have to use some sort of child class like the other posters have suggested. If you find a method that works, the developers will likely classify it as a bug in the future and break your code when you upgrade to the next version.
I recommend extending the class.
I'd think about what is the matter with the program design if I have to call a private function?
It used to be the case when
your class is responsible for several things (it is really two or thre calsses wrapped together) or
the rules of encapsulation are broken (utility functions, for example)
By finding any way to walk around this questions, you'll be nowhere nearer to the real solution.
Suppose your method declaration goes like so:
protected function getTheFoo() {
...
}
protected function setTheFoo($val) {
...
}
Usage:
$obj->__get('the_foo');
$obj->__set('the_foo', 'myBar');
This bypasses the protected methods and goes directly straight to the instance variables.