Jump to content

PHP Classes - Tricks for loading classes within classes


CrimpJiggler

Recommended Posts

I've been spending long hours learning about classes and their magic methods. I just came across a tutorial which showed a constructor like this:

class Device {
    //...
    public function  __construct(Battery $battery, $name) {
        // $battery can only be a valid Battery object
        $this->battery = $battery;
        $this->name = $name;
        // connect to the network
        $this->connect();
    }
    //...
}

the Battery part instantly caught my attention. Here had previously made a Battery class (and a more complete Device class) but the next thing he did really caught my interest:

$device = new Device(new Battery(), 'iMagic');
// iMagic connected
echo $device->name;
// iMagic

what the hell is going on here? Is this another way to include the methods and properties of one class into another class, in order words is this the same thing as:

class Device extends Battery

I don't think so because this new Battery() thing looks more like its creating an object inside the Device object. Previously the only way I could to that was to type $battery = new Battery() inside one of my methods. But this looks like hes doing something different. Can anyone explain whats going on here?

 

The whole tutorial is here:

http://code.tutsplus.com/tutorials/deciphering-magic-methods-in-php--net-13085

in the main Device method he has a premade $battery variable to hold the Battery object. Sometimes I have multiple classes containing functions which I'd like to include in my main class. I can only extend one class, so I usually extent a class containing only properties, no methods. I still don't know what difference making that info class abstract is, I'd appreciate if anyone could tell me.

 

Also I'd love to know what the point in static methods is. I've never used them because I've never seen the point. Is it just to make it easier to call the methods because you don't need to create an object instance to call them? Sorry for the extra questions, the first one is what I'm really wondering about.

 

 

Link to comment
Share on other sites

This is neither a special feature nor does it have anything to do with inheritance.

 

The code simply stores a Battery object in a property of a Device object. In other words, a device has a battery and may interact with it (draw energy from it etc.).

 

This is very different from inheritance. If you make Device a subclass of Battery, then you're saying that a device is a battery. That obviously doesn't make a lot of sense. A device may have a battery as one of its components, but it certainly doesn't have the behaviour and purpose of a battery.

 

Since this isn't inheritance, it certainly won't help you implement inheritance with multiple parent classes. If that's your goal, you should have a look at Traits.

Edited by Jacques1
Link to comment
Share on other sites

Objects can contain other objects. This is known as composition, and is used far more frequently than inheritance because, as Jacques says above, it creates a has-a relationship between objects rather than an is-a relationship that's formed with inheritance. It's more flexible.

 

The code above is simply doing something like this:

 

class Battery
{
    // stuff pertaining to a battery
}

class Device
{
    private $battery;
    private $name;

    public function __construct(Battery $battery, $name) // the uppercase Battery is a type hint, which makes the code more explicit
    {
        $this->battery = $battery;
        $this->name = $name;
    }

    // setters and getters
}
The part that's tripping you up isn't actually all that special. It's functionally the same as:

 

$battery = new Battery();
$name = 'something';

$device = new Device($battery, $name);
The only thing that's different is that instead of assigning the new Battery object to a variable, the code's author just creates it when they pass it as an argument to Device's constructor, likely because they won't need to access the Battery outside of the context of being a part of the Device.
Link to comment
Share on other sites

Brilliant explanations, nice one. So inheritence is what happens when I use "class1 extends class2" and inheretence means that every method and property from class2 becomes part of class one, kind of like if I have a function page and add include('functionspage2.php'). But this $__construct(Objectname $ObjectContainerVariable) thing is more like loading an instance of the Battery object into your Device objects instances. Is that it? I'm still a bit confused. The idea I have in mind, how I do it is like this:

class Battery {

}

class Device {
     public __construct() {
        $this->battery = new Battery();
    }
}

then that Battery instance is available to all my methods inside the Device class, and any classes that extent Device. Is this what you mean by me making Battery a subclass of Device, rather than Device having a Battery? An issue I have is lets say Device extends say my Config class, if I need to use the $battery instance inside my Config class I can't access it, I have to make a new instance. I've run into plenty issues like that so my method isn't very good, I'm hoping that this other method solves some of those issues for me. I haven't learned about traits yet but will ASAP, they sound interesting.

 

Nice one for the terminology, but I'm still  a bit confused about what inheritence and composition is. Is inheretence what happens when I extend one class with another? If so, then I get it. I see that like merging the two classes. Composition I'm guessing is where you add an instance object of a another class to your class so the second classes methods are contained in the $variable holding the instance.

Link to comment
Share on other sites

Is this what you mean by me making Battery a subclass of Device, rather than Device having a Battery?

No, the opposite. When classB extends classA you say that classB is a subclass of classA. If classA contains an instance of classB, classA has a classB.

 

An issue I have is lets say Device extends say my Config class

That would never make sense. A Device is not a Config. You only extend one class with another of the same Type.

Link to comment
Share on other sites

Oh yeah sorry, thats what I meant. What I meant about Config, is it I have a class containing properties common to all my classes. I used extend my classes with that Config class. I just learned about traits, this is brilliant, thanks a lot. This will solve my issues with chains of extended classes.

Link to comment
Share on other sites

Why would something in my website suddenly stop working when I haven't edited it in months. I have a website on a free server, which I recently upgraded to a premium account to host my other sites. When I went to that old site today, I get this error:

 

Parse error: syntax error, unexpected T_FUNCTION in [identifying info omitted] classes.php on line 162

 

Heres line 162:

$array_cartesian = function() use (&$array_cartesian) {

but in my experience errors like this are caused by something before the line with the unexpected code, heres the whole class:

class colorCombos {

	public function __construct() {


	}
	static public function get_combos() {
		$colors = array('blue', 'red',  'green');
		$array_cartesian = function() use (&$array_cartesian) {
			
			$args = func_get_args();

			if(count($args) == 0) {
				return array(array());
			} 
				
			$a = array_shift($args);
			$c = call_user_func_array($array_cartesian, $args);
			

			$r = array();
			foreach($a as $v) {

				foreach($c as $p) {
					$r[] = array_merge(array($v), $p);
				}
			}
			return $r;
		};

		$combo = $array_cartesian($colors,$colors);

		$combo_array['code'] = $combo_array['display'] = array_filter(
			$combo,
			function (&$row) { return ($row[0] !== $row[1]); }
		);


		$walk_call = function (&$row,$key) {
			$row = $row[0] . "-" . $row[1];
		};

		array_walk_recursive(
			$combo_array['display'],
			function(&$item,$key) { $item = ucwords($item); }
		);

		array_walk($combo_array['code'],$walk_call);
		array_walk($combo_array['display'],$walk_call);

		return $combo_array;
	}

}

Its for generating a list of combinations of two objects, in this case colours, so it'll output an array of items like red-blue, blue-green, green-red etc. It was working fine before, I don't know if it was right after upgrading the account that it happened or not, all I know is I didn't do anything myself to cause the error. Could that empty constructor be the problem? I rarely ever use static methods, I used it here just to learn, do I need to make the constructor static too?

Link to comment
Share on other sites

Objects can contain other objects. This is known as composition, and is used far more frequently than inheritance because, as Jacques says above, it creates a has-a relationship between objects rather than an is-a relationship that's formed with inheritance. It's more flexible.

 

The code above is simply doing something like this:

 

class Battery
{
    // stuff pertaining to a battery
}

class Device
{
    private $battery;
    private $name;

    public function __construct(Battery $battery, $name) // the uppercase Battery is a type hint, which makes the code more explicit
    {
        $this->battery = $battery;
        $this->name = $name;
    }

    // setters and getters
}
The part that's tripping you up isn't actually all that special. It's functionally the same as:

 

$battery = new Battery();
$name = 'something';

$device = new Device($battery, $name);
The only thing that's different is that instead of assigning the new Battery object to a variable, the code's author just creates it when they pass it as an argument to Device's constructor, likely because they won't need to access the Battery outside of the context of being a part of the Device.

 

What you said about the difference, I get that. No need to create an instance of an globally if you only need to create it inside your class, but the method I mentioned above does the exact same thing. I never had to add __construct(ExtraObject $ExtraObject) to the constructor, and to instantiate my class and make sure it instantiates the second class, I never had to do $instance = new MyClass(new ExtraClass()); I just put $this->ExtraClass = new ExtraClass(); inside the constructor function itself. I hope theres something I'm missing here because I was hoping this __construct(Object $object); would let me do something new.

 

Theres a problem I need to learn how to solve right now, I do a shitload of extending classes, I've been extending classes in chains and that can become a problem because sometimes the same class gets inherted twice. Another part of this problem is that only classes at the end of the chain have access to all methods, a class further up the chain can't access the class at the bottom because it hasn't extended it.

Link to comment
Share on other sites

Why would something in my website suddenly stop working when I haven't edited it in months. I have a website on a free server, which I recently upgraded to a premium account to host my other sites. When I went to that old site today, I get this error:

When your account was changed, it most likely also changed the version of PHP you are using. In this case likely to something older which does not support anonymous functions. If you have the ability to select your PHP version, make sure you are using PHP 5.3 or newer for that feature. If you can't control this yourself you'll have to ask your host to update.

 

What you said about the difference, I get that. No need to create an instance of an globally if you only need to create it inside your class, but the method I mentioned above does the exact same thing. I never had to add __construct(ExtraObject $ExtraObject) to the constructor, and to instantiate my class and make sure it instantiates the second class, I never had to do $instance = new MyClass(new ExtraClass()); I just put $this->ExtraClass = new ExtraClass(); inside the constructor function itself. I hope theres something I'm missing here because I was hoping this __construct(Object $object); would let me do something new.

By adding the battery as a parameter to the constructor it allows the code creating the device to control what kind of battery is used for the device. Say in the future you have several different types of battery classes, eg class NineVolt extends Battery, class TwelveVolt extends Battery, , class TwentyFourVolt extend Battery. All three of those classes are of type Battery and any of them could be passed into the constructor.

 

When you simply create the battery inside the object by doing $this->battery = new Battery you are creating a hard dependency between those two classes and do not allow for the ability to use different battery types in different instances of your device class.

 

If you want to learn a bit more, read up on Dependency Injection.

Edited by kicken
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.