Locking class members in PHP - php

In PHP, if you define a class, and then instantiate an object of that class, it's possible to later arbitrarily add new members to that class. For example:
class foo {
public $bar = 5;
}
$A = new foo;
$A->temp = 10;
However, I'd like the ability to make it impossible to add new members this way. Basically I want the class to ONLY have the members that are specified in its definition; if you try to set any other members, it fatally errors. The intent here is that I want to define a class as a very specific set of properties, and ensure that ONLY those properties exist in the class, so that the class contents are well-defined and cannot change later on (the values of each member can change, but not the members themselves).
I realize I can do this with the __set method, and simply have it fatal error if you try to set a member which doesn't already exist, but that's annoying to have to include in every class definition (although I could define each of my classes to extend a base class with that method, but that's also annoying). E.g.:
class foo {
public $bar = 5;
private function __set($var, $val) {
trigger_error("Cannot dynamically add members to a class", E_USER_ERROR);
}
}
Is there any other (preferably more convenient) way to do this? Aside from modifying PHP itself to disallow this behavior?

No. There's no better way than __set in a base class — yet. This is a known problem and is planned to be addressed in the future:
Introduce concept of “strict classes” that do not permit dynamic property creation

Nop, only __set. Perhaps you can use inheritance to avoid rewriting it everywhere.

I have to ask why you need to do this? If a member is assigned and does not exist it does not affect the methods, and if it is private it will throw an error. So why do you need to do this, or did I completely misread the question?

Related

Can php call a static alias?

In php, is it possible for a method in a parent class to use an alias in a child class from within an instance of the child class?
Parent class:
class ParentClass
{
public function getNewFoo()
{
return new Foo();
}
}
Child class:
use My\Custom\Path\To\Foo;
class ChildClass extends ParentClass
{
}
Code:
$child = new ChildClass();
return $child->getNewFoo();
I would like this code to return a new instance of My\Custom\Path\To\Foo() rather than a new instance of Foo().
I realize I can store the desired path to Foo in a class property, or I can simply instantiate the desired Foo in the child class. However, both of these seem redundant considering the path is already stored in the use statement in the child class.
You're asking a lot of PHP here. It's supposed to know that your use statement is going to impact something in a completely different class, in a completely different file, just because?
If PHP did that by default it would cause a lot of very strange problems for people. Re-define the method, or as you point out, store that property in the class itself.
I think a lot of developers would expect, or at least prefer that PHP behave the way it does.
It sounds like what you need here is a factory function that can be redefined in the subclass to behave differently, or in other words, that getNewFoo() should be overridden in the subclass to use the alternate version.

defining class variables in method?

Every example I've seen for defining a variable in a class, does so outside of any methods, for example:
class Testclass
{
public $testvar = "default value";
function dosomething()
{
echo $this->testvar;
}
}
$Testclass = new Testclass();
$Testclass->testvar = "another value";
$Testclass->dosomething();
How would you go about defining a variable inside a method, and making that definition available to any other method inside that class?
Note that I would only want to define the variable in one function, not have a different definition for each function.
I think you should read up on good object oriented practices. I mean, why do you want to make a variable available "inside a method"?
Variable's created within methods are local to that specific method and as such, scope is restricted to it.
You should instead use a instance member/variable which is available object wide if your trying to access a variable between methods. Or possibly you could pass the variable by ref between methods. Of course if its a value which never changes then it should be static variable on the class (class member).
I suggest having a read of the the OO tutorial on tutsplus. Tutsplus are generally great quality. http://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762
Alternatively, you could do the OO python course (intro to computer science) on Udacity - its also very high quality. Don't worry that its Python, specific language and syntax is irrelevant when trying to understand core OO concepts. https://www.udacity.com/course/cs101
Also, this is a common topic so have a search around, ie Passing Variables between methods?
I hope that helps
Edit: to address your comment. something like this:
class Testclass
{
private $csvResult = []; // instance member array to store csv results
function dosomething()
{
$this->$csvResult = fgetcsv($blah);
}
function processResult()
{
foreach ($this->$csvResult as $item) {
var_dump($item)
}
}
}
But again, as Adrian Cid Almaguer mentioned, you really are best to build a solid foundation of OO for yourself instead of just using this example without truly understanding it.
The real name of the variables class is "properties". You may also see them referred to using other terms such as "attributes" or "fields". In OOP (Object Oriented Programming) You can't define a property inside a method (the real name of a class function is method, not function), because this is a attribute of a class, not an attribute
of a method.
The properties define the attributes of a class, and the methods defines the behavior of a class. For example if you have a class named Person, the person have Name and Age, they are your properties, they are the attributes that describe your class, they can't be inside a method that describe a behavior of your class because the properties of your class must be accessed from any method that need it to show his behavior.
You can read some examples in:
http://www.killerphp.com/tutorials/object-oriented-php/

Are there best practices for working with static members in PHP?

PHP allows use of static member functions and variables, since 5.3 including late static bindings:
class StaticClass {
public static $staticVar;
...
}
$o = new StaticClass();
Currently, there are various options to access those static members:
$o->staticVar; // as instance variable/ function
$o::staticVar; // as class variable/ function
Other options exist for accessing members from inside the class:
self::$staticVar; // explicitly showing static usage of variable/ function
static::$staticVar; // allowing late static binding
Restructuring some existing classes that make some use of static members I've asked myself if there are best practices for working with static members in PHP?
Well, obviously, they all do different things.
$o->staticVar
This is invalid, since you cannot/should not access static properties with the instance property syntax.
StaticClass::$staticVar
This very plainly accesses a specific static variable on a very specific class.
$o::$staticVar
This accesses the static variable on the class that $o is an instance of. It's mostly used as a shorthand for the previous method and is equivalent in all respects. Obviously though, which class is used exactly depends on what class $o is an instance of.
self::$staticVar
This can be used only inside a class, and will always refer to the class that it's written in. It's a good idea to use this inside a class instead of StaticClass::$staticVar if the class refers to itself, since you don't need to worry about anything if you change the class name later. E.g.:
class Foo {
protected static $bar = 42;
public function baz() {
self::$bar; // good
Foo::$bar // the same, but should be avoided because it repeats the class name
}
}
static::$staticVar
This can also only be used inside a class and is basically the same as self above, but resolves with late static binding and may hence refer to a child class.
What the "best practice" is is debatable. I'd say you should always be as specific as necessary, but no more. $o::$staticVar and static::$staticVar both allow the class to vary through child classes, while self::$staticVar and StaticClass::$staticVar do not. Following the open/closed principle, it's a good idea to use the former, more variable method to allow for extensions.
Properties, both static and non-static, should also not be public to not break encapsulation.
Also see How Not To Kill Your Testability Using Statics.
First of all, don't use $this->staticVar. I am unsure when this changed (I believe PHP 5.4), but in recent versions it is no longer possible to retrieve static variables this way.
As for using late static binding, don't use it if you don't need it. The reason to use it would be if you plan to use inheritance and expect to change the value of the static variable in a derived class.

php constructor inheritance

I want to clarify a problem i am having
I have a base DataBase class that will be inherited by a bunch of other classes.The constructor looks like this:
public function __construct ($table)
{
$this->table = $table;
$this->db = new Database();
$this->db->connect();
}
I will call from this constructor from children as following:
public function __construct ($something)
{
parent::__construct("planets_games");
}
My problem is that php doesn't allow me to make the child's constructor without the $something parameter
i get the following:
Fatal error: Declaration of planetsGames::__construct() must be compatible with that of IScaffold::__construct()
I am currently bypassing this by instantiating an object like this:
$pg = new planetsGames('uselessStringHereThatHasNoUtilityAtAll');
I think i am missing something very important in my basic php knowledge
Thank you very much for the help in advance
This error message refers to the liskov substitution principle.
It applies to every IS-A relationship (which is the meaning of using inheritance (extends)) and states that every subtype should be fully replacable for the super type.
But this doesn´t apply to constructors! Which php version you are using?
It seems the base class has marked the constructor as abstract. That´s the only way
this error can appear.
You should never mark constructors abstract, final or put them in interfaces!
In most languages this isn´t even possible.
What you should take away from this is that the best-practice is that
each concrete object has a constructor with a signature that best
represents how a consumer should fully instantiate that particular
object. In some cases where inheritance is involved, “borrowing” the
parents constructor is acceptable and useful. Furthermore, it is
encouraged that when you subclass a particular type, that your new
type should, when appropriate, have its own constructor that makes the
most sense to the new subtype.
http://ralphschindler.com/2012/03/09/php-constructor-best-practices-and-the-prototype-pattern
A few years late to the party....
The problem is your constructor is needing a value. You can prevent the fatal error by setting a default value such as an empty string.
public function __construct($something = "")
{
parent::__construct("planets_games");
}
Then just instantiate the class like normal
$pg = new planetsGames();

PHP Inherited parent method can't access child's private property

First of all: A quite similar problem has been posted and somehow solved already, but is still not answering my specific problem. More about this later.
In words: I have a base class which provides some methods to all childs, but doesn't contain any property. My child is inheriting these methods, which should be used to access the child's properties.
If the child's property is protected or public, all works fine, but if the child's property is private, it fails without error (just nothing happens).
In code:
class MyBaseClass {
public function __set($name, $value) {
if(!property_exists($this, $name))
throw new Exception("Property '$name' does not exist!");
$this->$name = $value;
}
}
class ChildClass extends MyBaseClass {
public $publicProperty;
protected $protectedProperty;
private $privateProperty;
}
$myChild = new ChildClass();
$myChild->publicProperty = 'hello world'; //works of course!
$myChild->protectedProperty = 'hello world'; //works as expected
$myChild->privateProperty = 'hello world'; //doesn't work?
The above mentioned similar problem got the solution to use the magic __set() method to access the private properties, but this I am already doing. If I implement __set() within the child, it works of course, but the idea is, that the child inherits the __set() from it's parent, but obviously it can't access the child's private method.
Is that on purpose? Am I doinf something wrong? or is my approach just crap by design?
Background:
My original idea was: The whole dynamic thing about __set() is something I don't like. Usually a private property should never be accessible from outside, so I implemented throwing __set- and __get-methods in my ultimate base class (from which all classes inherit).
Now I want to dynamicially spawn an instance from an XML file and therefore need access to properties. I made the rule, that any XML-instantiatable class needs to implement the magic __set() method and so can be created dynamicially. Instead of implementing it in every Class that might be spawned some day, I decided to make them inherit from a class called like class Spawnable { } which provides the needed __set-method.
This is the difference between private and protected. Private methods and properties cannot be inherited or reached. You will need to change them to protected instead.
See the manual on visibility
Members declared protected can be
accessed only within the class itself
and by inherited and parent classes.
Members declared as private may only
be accessed by the class that defines
the member.
I guess you could fashion something using Reflection. For example, in your Spawnable class:
public function __set($name, $value)
{
$reflector = new ReflectionClass(get_class($this));
$prop = $reflector->getProperty($name);
$prop->setAccessible(true);
$prop->setValue($this, $value);
}
Not the prettiest of code, though.
After reviewing my concept, I think it's a bad idea, to go with that approach. This is a general issue with PHP's lack of differing between properties and fields. Of course private fields should never be accessible from outside, but only properties, which are defined by the programmer. The absence of auto-properties (and I don't mean these magical methods __set() and __get()) or some conventional rules for property access, makes it difficult to guess, which naming convention has been used by the programmer when implementing setters for private fields in his class.
The better concept here might be, to rely on the existence of well-named setters for each spawnable class, although it might break, if someone contributed code, which is not implementing the expected conventional named setters.
However, many thanks for your thoughts and hints!

Categories