Fairly new to classes in PHP, so bear with me.
class processRoutes
{
//Next line works
private $doc = "works as as string";
//Next line does not work, "Parse error: syntax error, unexpected T_NEW"
private $doc = new SimpleXMLElement('routingConfig.xml', null, true);
private function getTablenames()
{
//do stuff
}
}
I'm trying to ultimately utilize the SimpleXMLElement object within my class, among several private functions. What is the correct method for going about this, and why doesn't my current method work?
You need to do this in your constructor, as this can't be evaluated at this stage of script parsing. 'Simple' values, as strings, bools and numeric values will work though.
class processRoutes
{
//Next line works
private $doc = "works as as string";
private $doc;
public function __construct()
{
$this->doc = new SimpleXMLElement('routingConfig.xml', null, true);
}
// ....
}
You're attempting to initialise a property with an object instance, but you're only allowed to initialise variables with constants that can be determined at "compile time".
From PHP Manual - Properties
This declaration may include an initialization, but this initialization must be a constant value--that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.
Any initialisation that depends on "run time" knowledge will need to be executed either
in a constructor (refer #Dan-Lee's answer on how to implement this) that operates on $this->doc,
from within eg a "initialiser" function called from your constructor (you might do this to keep the "initialisation" steps distinct from other "real work" that might be done from your constructor), or
manually by your class's consumer. The consumer may operate
directly on the properties or your object (eg myProcessRoutes->doc = 'some other string'),
via a function call to your object eg myProcessRoutes.initialise_doc('some other string'), or
via a setter on your object - I'll let you research those, as I've not used these in PHP! ;-)
(Although it's arguable/philosophical if these approaches that occur later than instantiation/constructor are really initialisation).
The point of class constructors/destructors is to provide a "hook" by which the object instance can be initialised/disposed as required.
You might just need to create some specific new instances as per your example, in which case you don't need to accept any input to the constructor from the consumer.
Or, you might need to accept some values in order for your class to be set up properly. This is exactly what's happening in your example code above, when you're calling
private $doc = new SimpleXMLElement('routingConfig.xml', null, true);
(that is, you're passing the values of 'routingConfig.xml', null and true in to your new instance of SimpleXMLElement, so that this instance's constructor can initialise the instance using the values you passed to it, ready for use).
anytime you want to reference a class's variable, use the keyword $this
public function getTablenames()
{
$my_new_variable = $this->doc; // Transfers the $doc variable
}
Related
I am reading an article about constructors doing too much work.
One paragraph reads
In the object oriented style, where dependencies tend to be inverted, the constructor has a different and more Spartan role. Its only job is to make sure that object initializes into a state where it satisfies its basic invariants (in other words, it makes sure that the object instance starts off in a valid state and nothing more).
Here is a basic example of a class. On creation of the class I pass in the HTML which needs parsed to then set the class properties.
OrderHtmlParser
{
protected $html;
protected $orderNumber;
public function __construct($html)
{
$this->html = $html;
}
public function parse()
{
$complexLogicResult = $this->doComplexLogic($this->html);
$this->orderNumber = $complexLogicResult;
}
public function getOrderNumber()
{
return $this->orderNumber;
}
protected function doComplexLogic($html)
{
// ...
return $complexLogicResult;
}
}
I'm calling it using
$orderparser = new OrderHtmlParser($html);
$orderparser->parse()
$orderparser->getOrderNumber();
I use a parse function because I dont want the constructor to be doing any logic as both the article above and this article state this is terrible practice.
public function __construct($html)
{
$this->html = $html;
$this->parse(); // bad
}
However if I don't use the parse method, then all my properties (in this example just the one) would return null.
Is this known as an object in an 'invalid state'?
Also, it somewhat feels like my parse method is an initialise function in disguise, which is also deemed bad by the other article (although im not sure if that is only when a constructor calls that method, when it is manually called or both). Regardless, the initialise method is still doing some complex logic prior to setting a property - which needs to happen before the getters can be reliably called.
So either I am misunderstanding these articles or these articles are pushing me to think that maybe my overall implementation of this simple class is incorrect.
Generally, it's a code smell to perform work in a constructor, but the reason behind the practice has more to do with the programming language than an opinion about best practices. There are real edge cases that will introduce bugs.
In some languages derived classes have their constructors executed from the bottom up, and in other languages from the top down. In PHP they are called from top to bottom and you can even stop the chain by not calling parent::__construct().
This creates unknown state expectations in base classes, and to make matters worse PHP allows you to either call parent first or last in a constructor.
For Example;
class A extends B {
public __construct() {
$this->foo = "I am changing the state here";
parent::__construct(); // call parent last
}
}
class A extends B {
public __construct() {
parent::__construct(); // call parent first
$this->foo = "I am changing the state here";
}
}
In the above example class B has it's constructor called in different orders and if B was doing a lot of work in the constructor, then it might not be in the state the programmer was expecting.
So how do you solve your problem?
You need two classes here. One will contain the parser logic and the other the parser results.
class OrderHtmlResult {
private $number;
public __construct($number) {
$this->number = $number;
}
public getOrderNumber() {
return $this->number;
}
}
class OrderHtmlParser {
public parse($html) {
$complexLogicResult = $this->doComplexLogic($this->html);
return new OrderHtmlResult($complexLogicResult);
}
}
$orderparser = new OrderHtmlParser($html);
$order = $orderparser->parse($html)
echo $order->getOrderNumber();
In the above example you could have the parse() method return null if it fails to extract the order number, or throw an example. But neither class ever enters into an invalid state.
There is a name for this pattern, where a method yields another object as the result in order to encapsulate state information, but I remember what it's called.
Is this known as an object in an 'invalid state'?
Yes. You're exactly correct that the parse method is an initialise function in disguise.
To avoid the initialization parsing, be lazy. The laziest approach is to eliminate the $orderNumber field and parse it from the $html inside of the getOrderNumber() function. If you expect that function to be called repeatedly and/or you expect the parsing to be expensive, then keep the $orderNumber field but treat is as a cache. Check it for null inside of getOrderNumber() and parse it out only on the first invocation.
Regarding the linked articles, I agree in principle that constructors should be limited to field initialization; however, if those fields are parsed from a block of text and the expectation is that clients will utilize most or all of the parsed values, then lazy initialization has little value.
Furthermore, when the text parsing does not involve IO or newing up domain objects, it should not impede blackbox testing, for which eager vs. lazy initialization is invisible.
One of the common problems that occurs when the constructor does "too much" is that two objects that are somewhat closely linked need to reference each other (Yes, the close linking is a bad smell, but it happens).
If Object A and Object B must reference each other in order to be "Valid", then how do you create either?
The answer is usually that your constructor makes objects that are not fully "Valid", you add the reference to the other invalid object and then you call some kind of finalize/initialize/start method to finish and make your object valid.
If you still want to be "Safe", you can protect your business methods by throwing a not initialized exception if it's called before the object is "Valid".
Dependency Injection has a generalized version of this problem, what if you had a circular loop of injected classes? Following the construct/initialize pattern solves the general case too, so DI just always uses that pattern.
Addressing the question in the title I have always viewed an object as being in a valid state when it can perform its work without any issues; that is to say, it works as expected.
In looking at the linked article what jumped out at me was that the constructor logic was creating a lot of objects: I counted 7. All of these objects were tightly coupled with the class in question (ActiveProduct) as they were referenced directly and the constructor was passing the this pointer to the other objects constructors:
VirtualCalculator = new ProgramCalculator(this, true);
DFS = new DFSCalibration(this);
In this case ActiveProduct has not yet completed its initialization yet ProgramCalculator and DFSCalibration can call back into ActiveProduct via methods and properties and cause all sorts of mischief so for this reason the code is highly suspect.
In general in OOP you want to be passing objects to the constructor not instantiating them in the constructor. Also you want to employ the Dependency Inversion Principle and use interfaces or abstract / pure virtual classes when passing objects to constructors which would allow for dependency injection.
In the case of your class OrderHtmlParser this doesn't seem to be an issue as the complex logic at issue doesn't appear to go outside of the OrderHtmlParser class. I was curious as to why the doComplexLogic function was defined as protected, implying that inheriting classes can call it.
That said how to deal with initialization may be as simple as making the Parse method static and using it to construct the instance of the OrderHtmlParser class and make the constructor private so that the caller has to call the Parse method to get an instance:
OrderHtmlParser
{
protected $html;
protected $orderNumber;
private function __construct()
{
}
public static function parse($html)
{
$instance = new OrderHtmlParser();
$instance->html = $html;
$complexLogicResult = $instance->doComplexLogic($this->html);
$instance->orderNumber = $complexLogicResult;
return $instance;
}
public function getOrderNumber()
{
return $this->orderNumber;
}
protected function doComplexLogic($html)
{
// ...
return $complexLogicResult;
}
}
I fully agree with the comment from #trincot:
When you create the Parser with the Constructor, there is no need to pass the html.
Maybe you want to use the Parser Object a second Time with another Input.
So to have a clean constructor, I use a reset() Function, which is also called in the Beginning and which resets the initial State of the Object.
Example:
class OrderHtmlParser
{
protected $html;
protected $orderNumber;
public function __construct()
{
$this->reset();
}
public function reset()
{
$this->html = null;
$this->orderNumber = null;
}
/**
* Parse the given Context and return the result
*/
public function parse($html)
{
// Store the Input for whatever
$this->html = $html;
// Parse
$complexLogicResult = $this->doComplexLogic($this->html);
// Store the Result for whatever
$this->orderNumber = $complexLogicResult;
// return the Result
return $this->orderNumber;
}
public function getOrderNumber(){}
protected function doComplexLogic($html){}
}
Like this, the Parsing Object can do, what it is supposed to do:
Parse as often as you want:
$parser = new OrderHtmlParser();
$result1 = $parser->parse($html1);
$parser->reset();
$result2 = $parser->parse($html2);
Thank you for the excellent question!
This is an error-prone design to pass extensive data to the constructor that will merely store it inside the object to process this large data later.
Let me quote your beautiful quote again (the bold mark is mine):
In the object oriented style, where dependencies tend to be inverted, the constructor has a different and more Spartan role. Its only job is to make sure that object initializes into a state where it satisfies its basic invariants (in other words, it makes sure that the object instance starts off in a valid state and nothing more).
The design of the parser class in your example is troublesome because the constructor takes the input data, which is real data to process, not just “initialization data” as mentioned in the quote below, but does not actually process the data.
According to professor Ira Pohl from the University of California, Santa Cruz, the main roles of constructors are: (1) initialize the object, (2) convert values when a class has different constructor each having a different list of arguments - this concept is known as constructor overloading, (3) check for correctness - when the constructor parameters are checked to belong to a legal range.
Anyway, even if constructors are meant to initialize, convert and check, it happens very quickly, without significant delays.
In the very old programming courses, in 1980-s, we were told that a program has input and output.
Think of the $html as of the program input.
The constructors are not supposed to accept the program input. They are only supposed to accept the configuration, initialization data like character set name or other configuration parameters that may not be provided later. If they accept large data, they will likely be needed to sometimes throw exceptions, and exceptions in a constructor is a very bad style. Exceptions in constructors should better be avoided to make the code easier to fathom. For example, you may pass a file name to the constructor, but you should not open files in the constructor, and so on.
Let me modify your class a little bit.
enum ParserState (undefined, ready, result_available, error);
OrderHtmlParser
{
protected $orderNumber;
protected $defaultEncoding;
protected ParserState $state;
public function __construct($orderNumber, $defaultEncoding default "utf-8")
{
$this->orderNumber = $orderNumber;
$this->defaultEncoding = $defaultEncoding;
$this->state = ParserState::ready;
}
public function feed_data($data)
{
if ($this->state != ParserState::ready) raise Exception("You can only feed the data to the parser when it is ready");
// accumulate the data and parse it until we get enough information to make the result available
if we have enough result, let $state = ParserState::resultAvailable;
}
public function ParserState getState()
{
return $this->state
}
public function getOrderNumber()
{
return $this->orderNumber;
}
protected function getResult($html)
{
if ($this->state != ParserState::resultAvailable) raise Exception("You should wait until the result is available");
// accumulate the data and parse it until we get enough information to make the result available
}
}
If you conceive the class to have an evident design, programmers who use your class will not forget to call any method. The design in your original question was flawed because, contrary to the logic, the constructor did take the data but didn’t do anything with it, and a particular function was needed that was not obvious. If you make the design simple and obvious, you will not need even states. The states are only needed for classes that accumulate data for a long time until the result is ready, like state machines, for example, asynchronous reading of the HTML from the TCP/IP socket to feed this data to a parser.
$orderparser = new OrderHtmlParser($orderNumber, "Windows-1251");
repeat
$data = getMoreDataFromSocket();
$orderparser->feed_data($data);
until $orderparser->getState()==ParserState::resultAvailable;
$orderparser->getResult();
As for your initial questions about object states: if you design a class in such a way that the constructor only gets initialization data while there are methods that receive and process the data, so there are no separate functions to store the data and parse the data that may be forgotten to call – no states are needed. If you still need states for long-living objects that collect or supply the data sequentially, you may use the enumeration type like in the example above. My example is in abstract language, not a particular programming language.
I created a class implementing ArrayAccess and I added it a function to prevents WRITE actions:
$Obj->Add("key","something");
$Obj->Add("key2","something2");
$Obj->SetReadOnly(); // sets read only property
unset($Obj["key2"]); // throws error, object is readonly
But, i want to prevent unsetting object too:
unset($Obj);
I can do it?I hear suggestions.
Thanks for help!.
I can't imagine any situation where you would really want to do this. I can also imagine doing this will cause you serious problems at script termination when all objects are destroyed. The PHP manual says the following on throwing exceptions in destructors:
Note:
Attempting to throw an exception from a destructor (called in the time
of script termination) causes a fatal error.
The above statement implies that you can throw an exception if you're not in the script termination phase, so maybe the following is possible.
public function __destruct ()
{
if ($this -> isReadOnly ())
{
throw new Exception ('Class is read-only');
}
}
However, as the manual points out, this will trigger a fatal error during script shutdown.
I honestly can't see any point to wanting to prevent object destruction. It should be up to the programmer to manage object lifetimes.
unset() does not actually destruct an object, if that's what you're trying to prevent.
An object will only be destructed when all references to it have been unset or are no longer in scope. Even then it won't happen until the garbage collector runs.
So if you have some code that you are worried will molest your object, you've already done a good job of making it immutable with your read-only logic.
Let's say you have
$Obj = gotMyObjectSomehow();
and you need to pass it to a some other code you don't want to unset $Obj. As long as that code is called inside a function, there's nothing to be concerned about. If you call
someFunction($Obj);
and let's say that function unsets the parameter it's passed in
function someFunction($anObj) {
unset($anObj);
}
then your original $Obj variable will still be set.
The function creates a second variable referencing the original object and uses that in its own scope.
You can't control unsetting variable names, because those names are not technically a part of the object referenced. Consider the following:
$a = new MyObject();
$b = $a;
Now you have two references to the same object. There is no difference between using $a and $b, because in PHP objects are always used by reference (i.e. you don't have to do $b =& $a in the second line). So both $a and $b are essentially the same object; unsetting $a will not destroy the object, as well as unsetting $b won't destroy it; all references need to be unset before the object is destroyed.
I don't think you can do what you're asking for - it's not possible to prevent a variable being unset like that.
However, a comment of yours above set me thinking. You said:
.... idea if you want to prevent unsets system variables in a thirdparty extensions
So if I understand you right, your aim here is to ensure that while the thirdparty code (ie your software) is in use, all the variables associated with it remain in place?
Now you haven't specified much about what variables there are in this system. We see one object in the question, but presumably there must be more than that? I'm guessing you've got a bunch of things that tie together, right? It would help in these sorts of questions to provide a bit more context; the actual thing that you're asking for isn't possible, but with a bit of understanding about what you want to achieve, we could come up with alternatives.
Okay. So my suggestion: create your objects as Singletons. This is often frowned on by purists, but might work well for this situation, depending on exactly what you're doing. The beauty here is that you can encapsulate all access to the object inside class methods, meaning that the developer using your code doesn't have access to the master copy of the object in order to unset it.
A singleton works like this:
<?php
class mySingletonClass {
private static $masterObject=null;
public static function getInstance() {
if(!isset(self::$masterObject)) {
self::$masterObject = new self;
}
return self::$masterObject;
}
private function __construct() {
//your existing constructor, as it already exists, but marked as private.
}
//...and all the other methods as you already have them.
}
The class constructor method is private, so can only be accessed from methods within the class. Therefore, you can no longer do new classname(). The only way you can get an object of this class is to get it from the static getInstance() method. And the key thing here is that this method always returns the same copy of the object.
$obj = mySingletonClass::getInstance();
unset($obj);
$obj = mySingletonClass::getInstance(); //will give the exact same object as the first time.
You can unset it if you want, but the original object is still there and can still be accessed. Any of your other classes can use that getInstance() method to get the same copy of the same object from anywhere in the program. It's an indestructible global variable.
Singletons are often used for a program's main database connection object, but it might be a useful pattern for you here.
I hope that helps. It's about the only way I can think of to get close to what you want.
I was looking through the PHP documentation and saw several comments where a variable was initialized outside of a class's constructor, similar to the following:
classMyClass {
private $count = 0;
public function __construct() {
//Do stuff
}
}
In PHP Objects, Patterns, and Practice, the author recommends using constructs only for the initialization of properties, deferring any heavy lifting or complex logic to specialized methods. This tutorial (a quick example that I found on Google) also recommends using constructors to initialize properties: http://www.killerphp.com/tutorials/object-oriented-php/php-objects-page-3.php.
Why would you want to initialize a variable outside the constructor? Is this just sloppy coding, or is there a reason to do something like this? I have to say that until recently, I initialized default values outside the constructor, and there doesn't seem to be any programmatic advantage of one way over the other.
When you initialize a variable outside of the constructor, it must be initialized as a constant. You can't do any operation to initialize it. Thus, the initial value of that member is actually a part of the class signature.
For example, this is invalid:
private $var = $othervar;
private $var = func();
You could do it in the constructor as well, but it would be a bit more verbose and add some clutter to the constructor unless there was some sort of logic going on.
More a comment than an answer, but please elaborate here a little:
Since it is recommended to use constructors for property initialization only,
Who says this and why? I assume the only relates to something else than property definitions with default values.
An answer part:
By default in PHP variables do not need to be defined because variables are then defined when first accessed in a write context. All variables, including undefined ones contain NULL (Demo):
class A {}
$a = new A;
var_dump($a->property); # NULL
Introducing class variables (properties) PHP then allowed to actually define variables. Those still return NULL by default, but they are defined (Demo):
class A {
public $property;
}
$a = new A;
var_dump($a->property); # NULL
In the next step of the evolution, this language construct also allows to specify a constant expression. That is constant because definition is compile-time (not run-time as the when the constructor is invoked). An example (Demo):
class A {
public $property = 'hello';
}
$a = new A;
var_dump($a->property); # string(5) "hello"
As this is compile- but your constructor run-time, I find it hard to compare both feature with another. Also it's not clear why you say that initializing via the constructor is recommended.
Far from sloppy... it's good programming practice. As you would also do in Java/C++, it just sets them up, and then you can do any initialisation in the constructor - usually to sent them to non-defaults as such.
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).