I am currently digging into the basics of php class / constructor.
I understand how a constructor works but not why I should use it.
For example when I have a constructor like this:
function __construct($arg1, $arg2){
$this->name = $arg1;
$this->speed = $arg2;
}
Why should I use __constructor and not a simple callback like:
function foo($arg1,$arg2){
$this->name = $arg1;
$this->speed = $arg2;
}
Thank you
Doing
$obj = new Class($var1, $var2);
And
$obj = new Class($var1, $var2);
$obj->foo($var1, $var2);
Have the same end result
By forcing values to be passed on the constructor, class can define Mandatory values it should have in order to construct a class. As in the later case, one can ignore foo.
Having a method to initialize means, one ends up having different method names, foo, init etc, constructor avoids this
The constructor is always called on object instantiation and is a known pattern.
Your second example isn't (if it's intended to perform a similar initialisation role as the constructor).
<?php
class abc {
function __construct($arg1, $arg2){
echo $arg1.' '.arg2;
}
}
$obj = new abc('manish','jangir');
?>
It will print "manish jangir" automatically when the object is created
The main purpose is to keep your code clean. With placing your initialization in the constructor you can kan be sure the variable to be used in the other function will be in valid state for example :
class Foo{
private $number;
public function setNumber($number) {
$this->number = $number;
}
public function getNumber() {
if ($this->number=== null) {
throw new RuntimeException("The Number is Null !");
}
return number;
}
}
this is the class with constructor
class Foo{
private $number;
public function __construct($number) {
$this->number = $number;
}
public function getNumber() {
if ($this->number=== null) {
throw new RuntimeException("The Number is Null !");
}
return number;
}
}
with constructor you can be sure the number will be initialized. I hope my answer is clear enough but if you have another question about my answer feel free to ask in the comment :)
Related
I have a class 'base' and a class 'loader', which looks like this.
class base {
protected $attributes = Array();
public $load = null;
function __construct() {
$this->load = loader::getInstance();
echo $this->load->welcome(); //prints Welcome foo
echo $this->load->name; //prints Foo
echo $this->name; //doesnt print anything and i want it to print Foo
}
public function __get($key) {
return array_key_exists($key, $this->attributes) ? $this->attributes[$key] : null;
}
public function __set($key, $value) {
$this->attributes[$key] = $value;
}
}
class loader {
private static $m_pInstance;
private function __construct() {
$this->name = "Foo";
}
public static function getInstance() {
if (!self::$m_pInstance) {
self::$m_pInstance = new loader();
}
return self::$m_pInstance;
}
function welcome() {
return "welcome Foo";
}
}
$b = new base();
Now what I want is a way to store variables from loader class and access them from base class using $this->variablename.
How can I achieve this? I don't want to use extends. Any idea ?
I don't feel like you've fully understood what coding the OOP way means. And usually Singletons are code smells so I'll just warn you:
There's probably a better way of accomplish you goal. If you provide more informations we will help you out. In its current form the answer is the following; just remember that I higly discourage its implementation in your code.
Assuming that you want to access only public (and non static) loader's variables as this->varname in the base class you should just insert this line in the beginning of the base class constructor:
$this->attributes = get_object_vars(loader::getInstance());
This will basically initialize the attributes array with all the loader public vars so that via your __get() method you can access its value.
On a side note, take a look at Dependency Injection design pattern in order to avoid using Singletons.
Your __get/__set methods access $this->attributes but not $this->load.
You could e.g. do something like (pseudocode)
function __get($key) {
- if $attribute has an element $key->$value return $attribute[$key] else
- if $load is an object having a property $key return $load->$key else
- return null;
}
see also: http://docs.php.net/property_exists
You can make static variable and then you can access this variable from anywhere
public statis $var = NULL;
and you can access it like this
classname::$var;
What would be the best practice to do this :
class AwesomeClass {
// Code
public function test()
{
foreach($objects->values as $v)
{
New SuperClass($v);
}
return $objects;
}
}
class SuperClass {
public function __construct($arg2)
{
return trim($arg2);
}
}
$rule_the_world = New AwesomeClass($arg1);
$king = $rule_the_world->test();
The previous code is obviously not working, I think I'm missing some major point of PHP OO.
It's very difficult to decipher what you're asking for, and the code you have is not recoverable.
Code Errors
There are several errors in your code that are illogical:
AwesomeClass has no constructor.
This makes passing arg1 to new AwesomeClass meaningless
arg1 is never initialized
In AwesomeClass::test(), objects is never initialized and has no member value.
You will get a warning since it's not traversable
New SuperClass (should be new, per standards) does nothing.
__construct() cannot return a value.
What You May Want
What I think you're going for is something like this:
class AwesomeClass implements IteratorAggregate {
private $arg1;
public function __construct(array $arg1) {
$this->arg1 = $arg1;
}
public function getIterator() {
return new ArrayIterator($this->arg1);
}
}
class SuperClass {
private $arg2;
public function __construct($arg2) {
$this->arg2 = $arg2;
}
public function __toString() {
return "$this->arg2\n";
}
}
$rule_the_world = new AwesomeClass(array('one', 'two', 'three'));
foreach ($rule_the_world as $sc) {
$sc = new SuperClass($sc);
echo $sc;
}
Note that it is redundant to create an ArrayIterator instance when arg1 must already be an array, this is just an example.
How this stuff works?
$object->foo1()->foo2()->foo3();
I'm working in Magento php framework. In Magento functions are called as sequence.But, I don't understand how it works.Can anyone explain.
$object->foo1()->foo2()->foo3();
First, PHP will get a pointer to the foo1 method from the $object variable. It calls this method, which then returns another object. This second object (we shall call it $object2) has a method foo2(), which is also called. foo2() returns another object ($object3), which has a method foo3(), which returns whatever it likes.
In some cases, $object, $object2 and $object3 are just pointers to the same object. This means that you can keep calling methods on the same class in a nice sequence.
You can achieve this quite easily:
class Foo
{
public function nicely()
{
return $this;
}
public function formatted()
{
return $this;
}
public function chained()
{
return $this;
}
public function calls()
{
return $this;
}
}
$foo = new Foo();
$foo->nicely()->formatted()->chained()->calls();
When the methods in the class are returning values, they are returning objects of themselves. This allows you to keep calling other methods in that class in a sequence like you posted.
class myClassA {
public $str = NULL;
public function setStr( $value ){
$this->str .= $value;
return $this; // This is the key to sequencing
}
}
$myclass = new MyClassA();
$myclass->setStr("H")->setStr("E");
// If you echoed the $str variable in myClassA, you would get
// "HE"
How do I use an object (along with its methods and properties) when I'm inside an object?
Say I have useless classes like these:
class Fruit {
private $name; // Name of the fruit.
private $health = 10; // 0 is eaten, 10 is uneaten.
private $object; // This is a PHP object.
public function __construct($name) {
$this->name = $name;
}
public function set($varname,$value) {
$this->$varname = $value;
}
}
class Eater {
private $name;
public function eat($object) {
$object->set('health',0); // I know I can pass and modify objects like this.
// The object is passed by reference in PHP5 (but not 4), right?
}
}
And I use it as such:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->eat($apple);
?>
But if I modify the Eater class like so:
class Eater {
private $name;
private $objectToEat; // Let's say if I need the object to be over here instead of in a method.
public function set($varname,$value) {
$this->$varname = $value;
}
public function eat() {
$this->objectToEat->set('health',0); // This doesn't work!
}
}
And set the main program like so:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->set('objectToEat',$apple);
$paul->eat();
?>
How can I access the object's properties from inside a method? I know I use $this->objectToEat to tell PHP I'm talking about the class properity, but since that property is an object, how do I access the object's methods?
I've tried $this->objectToEat->set('health',0) but that doesn't work. I hope you guys understand what I'm trying to get at (sorry, I can't figure out how to condense my question without compromising clarity)!
You have to set the property correctly. Since it's private, you can't do this from outside the object, so you have to use encapsulation:
class Eaters {
private $name;
private $objectToEat;
public function eat() {
$this->objectToEat->set('health',0); // Assumed "object" was just a typo
}
public function setObjectToEat($object) {
$this->objectToEat = $object;
}
}
Then use it like so:
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->setObjectToEat($apple);
$paul->eat();
?>
Note: In this brief example, your original method is a better design. In certain cases, you might want to prime the method to be used by setting properties beforehand, but more often you want to call it with parameters directly, since it's more clear and more reusable (compartmentalized).
This answer modifies Renesis' answer
In the class, the object to eat is a private variable hence you can't go
$paul->objectToEat = $apple;
What you can do is to make a setter method inside Eaters
class Eaters {
private $name;
private $objectToEat;
public function eat() {
$this->objectToEat->set('health',0); // Assumed "object" was just a typo
}
public function setFood($object) {
$this->objectToEat = $object;
}
}
Therefore, you can call the setFood() method instead.
OR
Change eat() to
public function eat($object) {
$this->object->set('health',0);
return $object;
}
Saving the modified object back to the original variable.
OR
class Eaters {
private $name;
public function eat(&$object) { // this passes object by reference
$object->set('health', 0);
}
}
Although this code is not tested, that is how you can pass a variable by reference.
NOTE: You only need the & when defining the method not when you're passing an argument. For more info about Passing by Reference go to this link
It's probably because your eat method isn't accepting any parameters, and the Eaters class has no $object property.
Can you make $objectToEat a reference and then use it as such in the eat() function?
you have to set $this->object in class Eaters
function __construct($object){
$this->object = $object;
}
or
<?php
$pear = new Fruit("Pear");
$apple = new Fruit("Apple");
$paul = new Eater("Paul");
$paul->eat($apple);
?>
class Tester {
private $variable;
private $anObj;
public function testFn($val) {
$this->variable = $val;
$this->anObj = new SecondObj();
$this->doSomething();
}
public function doSomething() {
echo("My variable is set to " . $this->variable);
$this->anObj->wow();
}
}
class SecondObj {
public function __construct() {
echo("I'm new!");
}
public function wow() { echo("Wow!"); }
}
$tester = new Tester();
$tester->testFn(42);
Output:
I'm new!My variable is set to 42Wow!
I have a singleton factory and would like it to return a reference to the object instance so that I can use the singleton factory to destroy the instance and not have instances elsewhere in my code to survive.
Example of what I would like to be able to do:
$cat = CatFactory::getInstance();
$cat->talk(); //echos 'meow'
CatFactory::destructInstance();
$cat->talk(); //Error: Instance no longer exists
This could work:
<?php
class FooFactory
{
private static $foo;
private function __construct()
{
}
public static function getInstance()
{
return self::$foo ? self::$foo : (self::$foo = new FooFactory());
}
public static function destroyInstance()
{
self::$foo = null;
}
public function __call($fn, $args)
{
if (!method_exists(self::$foo, $fn) || $fn[0] == "_")
throw new BadMethodCallException("not callable");
call_user_func_array(array(self::$foo, $fn), $args);
}
# function hidden since it starts with an underscore
private function _listen()
{
}
# private function turned public by __call
private function speak($who, $what)
{
echo "$who said, '$what'\n";
}
}
$foo = FooFactory::getInstance();
$foo->speak("cat", "meow");
$foo->_listen(); # won't work, private function
FooFactory::destroyInstance();
$foo->speak("cow", "moo"); # won't work, instance destroyed
?>
Obviously it is a hack.
Based on the documentation for unset, I do not think that is possible. You cannot actually destroy an object, only a handle to it. If other variables are around that still hold a reference, the object will continue to live on.
You can accomplish what you want by having your Cat object enforce a private $destroyed property. PHP 5 passes objects by reference by default, so you don't have to worry about that part.
A work around would be creating a cat class
class cat
{
public $cat;
public function __construct()
{
$this->cat = CatFactory::getInstance();
}
public function __destruct()
{
CatFactory::destructInstance();
}
}
$cat = new cat();
$cat->cat->talk();
$cat->cat->talk();