When I call this function, and add a constructor to my class, all my class properties are already set. How is that possible -- I thought you had to construct a class before you could set its properties?
I guess that PDO uses some internal code to create an object without invoking the constructor. However it is possible to instance a new object without calling the constructor even in pure PHP, all you have to do is to deserialize an empty object:
class SampleClass {
private $fld = 'fldValue';
public function __construct() {
var_dump(__METHOD__);
}
// getters & setters
}
$sc = unserialize(sprintf('O:%d:"%s":0:{}', strlen('SampleClass'), 'SampleClass'));
echo $sc->getFld(); // outputs: fldValue, without calling the construcotr
As of PHP 5.4.0+ ReflectionClass::newInstanceWithoutConstructor() method is available in reflection API.
In php, any array can be cast to an object. My assumption is pdo creates an associative array an then jus casts it. I dont know if he constuctor is called on cast...
Actually, a cast isnt the right word, a conversion occurs behind the scenes. Read this. Blurb on what happens: http://php.net/manual/en/language.types.object.php
Related
In my current application I have a number of objects that are required repeatedly
To save overhead of instantiating the same object over and over again, I keep an array of 'known' objects.
I can check the input data against the array, and - if already set - use the existing object, else go ahead to instantiate the new object and add the pointer reference to the relevant known objects array.
In most use cases, I can check prior to instantiating the class:
if(array_key_exists($identifier,$known_ClassObjects)){
$object = $known_ClassObjects[$identifier];
} else {
$object = new Class($params);
}
However, in some cases I can only identify that the object I am instantiating already exists once already inside it.
In that case I would like to be able to do one of 2 things:
return the OTHER (pre-existing) object instead of this one, e.g.
class Test{
public function __construct($params){
//apply processing to $params, resulting in $identifier
if(array_key_exists($identifier, $known_ClassObjects)){ //$known_ClassObjects is global
return $known_ClassObjects[$identifier];
} else {
//continue __construct() logic
return $this;
}
}
}
However, PHP ALWAYS returns the current object, even with code return $other_object;
'Internally Clone' the current object from the found one [of the same class, obv] so that when it returns, it has the correct relevant properties populated.
NOTE: including any parent/child class properties
-> I want to make this object EXACTLY the same as the found one.
So, if there was a PHP function clone_from(), it would work something like:
if(array_key_exists($identifier,$known_ClassObjects)){
$this->clone_from ($known_ClassObjects[$identifier]);
} else {
//continue with __construct()
}
return $this;
Given that 1. doesn't work and 2. doesn't seem to exist, I have only been able to do this in very 'hacky' ways: iterating through all properties of source object and setting all properties of current object.
However, this has obvious issues esp. with extended parent/child classes etc. which then requires things like reflection classes.
This seems like there SHOULD be a really simple solution, but I have been unable to find one
What you actually could do is using either a Singleton Pattern or a Factory pattern - in both cases, the creation of objects is controlled by some piece of code and you can decide, which object to return. Singleton already is a special form of a Factory pattern.
Consider this code
class Singleton {
protected static $instance;
protected function __construct() {
}
public static function instance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
The constructor is protected which will prevent a object construction from "outside" via new. However, there is also a static function instance with which somebody can request an object instance from the factory method.
$obj = Singleton::instance();
So, the (internal) object is created only once, and then delivered afterwards until the script ends.
However, PHP ALWAYS returns the current object, even with code return $other_object;
Constructor is not a regular function. You do not return from it. If you are in __construct() you are already constructing the new object. Before proceed, I strongly recommend you read at least: https://www.php.net/manual/en/language.oop5.decon.php
You most likely need a helper method or factory that would deal with that instead. Putting the logic you tried to place into your constructor is wrong.
Also you missed to clarify what the $identifier really is. But if that's object's property, then you can expose it (i.e. via getter) and have it read for your comparison/whatever by other code.
How can I ensure that an object will be instantiated only via another particular object?
For example, say I have a Registry object to store my Mappers. When client code calls the get() method on the Registry, it lazy loads and returns the requested Mapper. That's fine, except there is nothing to stop client code from creating a duplicate instance of the Mapper using the new operator.
The only option I can think of is that my Mappers require a Registry object as a parameter. Are there other options?
What do you do? Should I even bother about preventing this kind of duplication?
Perhaps you should not try to prevent people from creating instances themselves? If you don't trust yourself or your colleagues not to instantiate objects in places where they should not instantiate them, you have a problem.
If the mappers do not need a registry to function, you should not object it via the constructor. Passing it to some static method seems rather odd, and makes your code less flexible since you're using static. And how are you going to unit test the mappers, without writing some hacks to properly instantiate them via the registry you should not have need for in these tests? Good post on that here: http://kore-nordmann.de/blog/0103_static_considered_harmful.html
You can't protect from the new operator. What you could do though is that you have a get() method in your class to make your class/object singleton (or using a Registry as you do).
class clTest {
private static $oInstance;
public static function get() {
if( !self::$oInstance ) {
self::$oInstance = new clText;
}
return self::$oInstance;
}
}
if you wish to prevent outside instantiation you only need to declare __construct as private and then use a call to a static method to get an instance of the Mapper class. You can then pass in an instance of the registry class and only return a new instance if the parameter is an instance of the registry class.
class Mapper{
private __construct(){}
public static function getInstance($registry){
if($registry instanceof Registry){
return new Mapper();
}
}
}
$registry = new Registry();
$mapper = Mapper::getInstance($registry);
Hello I would like to store or save an object inside a session,using classes like SessionHandler or arrays $_SESSION,I've seen that it is possible if I serialize the object,and I don't want to lose the methods of that object instance..
I've seen seralizing it is possible but the objects what I want to store is created by PDOStatement::fetchObject() althought the instance class is "Users" I get this error:
PDOException: You cannot serialize or unserialize PDO instances
Why? It is not a PDO instance..
Sorry I am spanish and I don't speak english very well..
Thanks
PHP's native $_SESSION sessions transparently serialize and unserialize objects that support PHP's serialization protocol or the Serializable interface. You do not need to explicitly serialize them.
PHP cannot serialize resources because these are handles to some stateful resource outside PHP's control. This is why you cannot serialize PDO or PDOStatement objects.
By default an object is serialized by saving all property names and values and unserialized by creating an object with the same class (without invoking the constructor) and directly setting the serialized properties. You can customize serialization behavior for your objects using the __sleep and __wakeup magic methods or by implementing the Serializable interface. But not both! If you use implements Serializable, __sleep and __wakeup are ignored.
One important note: when using object serialization, you must have the class definition loaded before you unserialize (or have an autoloader that can load it) and it must match the class definition of the object that was serialized. Class definitions are not stored in the serialized data.
For example suppose you have the following:
class Test {
public $version = 1;
protected $abc;
public function setAbc($abc) {
$this->abc = $abc;
}
}
$t = new Test();
$t->setAbc(123);
$_SESSION['mytest'] = $t;
Now imagine you change Test one day to be like this instead:
class Test {
public $version = 2;
private $def;
public function setDef ($def) {
$this->def = $def;
}
}
Now suppose you load into your new code an object serialized when Test was at version 1:
$t = $_SESSION['mytest']; // this was stored yesterday, when Test was version 1
var_dump($t)
You will get this:
object(Test)#1 (3) {
["version"]=>
int(1)
["def":"Test":private]=>
NULL
["abc":protected]=>
int(123)
}
Furthermore, you can't use old methods:
if ($t->version == 1) { // Check for class version
$t->setAbc(345); // "Fatal error: Call to undefined method Test::setAbc()"
}
In my quest in trying to learn more about OOP in PHP. I have come across the constructor function a good few times and simply can't ignore it anymore. In my understanding, the constructor is called upon the moment I create an object, is this correct?
But why would I need to create this constructor if I can use "normal" functions or methods as their called?
cheers,
Keith
The constructor allows you to ensure that the object is put in a particular state before you attempt to use it. For example, if your object has certain properties that are required for it to be used, you could initialize them in the constructor. Also, constructors allow a efficient way to initialize objects.
Yes the constructor is called when the object is created.
A small example of the usefulness of a constructor is this
class Bar
{
// The variable we will be using within our class
var $val;
// This function is called when someone does $foo = new Bar();
// But this constructor has also an $var within its definition,
// So you have to do $foo = new Bar("some data")
function __construct($var)
{
// Assign's the $var from the constructor to the $val variable
// we defined above
$this->val = $var
}
}
$foo = new Bar("baz");
echo $foo->val // baz
// You can also do this to see everything defined within the class
print_r($foo);
UPDATE:
A question also asked why this should be used, a real life example is a database class, where you call the object with the username and password and table to connect to, which the constructor would connect to. Then you have the functions to do all the work within that database.
The idea of constructor is to prepare initial bunch of data for the object, so it can behave expectedly.
Just call a method is not a deal, because you can forget to do that, and this cannot be specified as "required before work" in syntax - so you'll get "broken" object.
Constructors are good for a variety of things. They initialize variables in your class. Say you are creating a BankAccount class. $b = new BankAccount(60); has a constructor that gives the bank account an initial value. They set variables within the class basically or they can also initialize other classes (inheritance).
The constructor is for initialisation done when an object is created.
You would not want to call an arbitrary method on a newly created object because this goes against the idea of encapsulation, and would require code using this object to have inherent knowledge of its inner workings (and requires more effort).
In my quest in trying to learn more about OOP in PHP. I have come across the constructor function a good few times and simply can't ignore it anymore. In my understanding, the constructor is called upon the moment I create an object, is this correct?
But why would I need to create this constructor if I can use "normal" functions or methods as their called?
cheers,
Keith
The constructor allows you to ensure that the object is put in a particular state before you attempt to use it. For example, if your object has certain properties that are required for it to be used, you could initialize them in the constructor. Also, constructors allow a efficient way to initialize objects.
Yes the constructor is called when the object is created.
A small example of the usefulness of a constructor is this
class Bar
{
// The variable we will be using within our class
var $val;
// This function is called when someone does $foo = new Bar();
// But this constructor has also an $var within its definition,
// So you have to do $foo = new Bar("some data")
function __construct($var)
{
// Assign's the $var from the constructor to the $val variable
// we defined above
$this->val = $var
}
}
$foo = new Bar("baz");
echo $foo->val // baz
// You can also do this to see everything defined within the class
print_r($foo);
UPDATE:
A question also asked why this should be used, a real life example is a database class, where you call the object with the username and password and table to connect to, which the constructor would connect to. Then you have the functions to do all the work within that database.
The idea of constructor is to prepare initial bunch of data for the object, so it can behave expectedly.
Just call a method is not a deal, because you can forget to do that, and this cannot be specified as "required before work" in syntax - so you'll get "broken" object.
Constructors are good for a variety of things. They initialize variables in your class. Say you are creating a BankAccount class. $b = new BankAccount(60); has a constructor that gives the bank account an initial value. They set variables within the class basically or they can also initialize other classes (inheritance).
The constructor is for initialisation done when an object is created.
You would not want to call an arbitrary method on a newly created object because this goes against the idea of encapsulation, and would require code using this object to have inherent knowledge of its inner workings (and requires more effort).