PHP OOP - Properties and methods

Last revision:

Class properties

Objects typically represent state (data) and behavior (functionality).

To represent data, classes use properties: variables that are part of the class definition.

Properties must have at least two things: a name, and an access modifier that specifies the property's visibility: public, private, or protected:

Code
<?php

class Phone {

 public $brand;

}

For now it's perfectly fine to keep everything public. You'll learn more about access modifiers later.

Let's create a Phone instance using the new keyword,  and set the brand to "Samsung":

Code
<?php

class Phone {

 public $brand;

}

$myphone = new Phone();

$myphone->brand = 'Samsung';

Pay attention to the last line. The object operator (->) is used to access the "brand" property on the $myphone object. Notice that there's no $ sign between the arrow and the property name: $object->property_name.

You can now print your phone's brand:

Code
<?php

class Phone {

  public $brand;

}

$myphone = new Phone();

$myphone->brand = 'Samsung';

print $myphone->brand;

Note
You will learn later that it is NOT a good practice to mix the class definition with code that uses that class in the same file. 

A class should go into its own file, and that class file should be referenced using one of methods PHP provides for this.

For now it's fine to use a single file to keep things as straightforward as possible.

Do not skip the next activity, which shows you how to run a PHP script from the command-line.

Activity 1

  • Recreate the PHP script that sets and prints the phone brand. 
  • Save it as myphone.php.
  • run it with php -f myphone.php

You can either run this from your terminal application or from a terminal inside VSCode.

If everything went well, the brand name should have been printed.

Activity 2

It might be a bit hard to read the output of the previous script since it sticks to your command-line prompt.

A quick fix is to add a newline before and after the value you want to print on screen. There are several ways to do this; using the PHP_EOL (End Of Line) reserved constant ensures that the correct line ending characters are used on your system.

Answer / solution
print PHP_EOL;
print $myphone->brand;
print PHP_EOL;

Multiple properties

Of course classes can have more than one property. You can add as many as you need:

Code
<?php

class Phone {

 public $brand;
 public $color;
 public $model;
 public $price;

}

Activity 3

  • Instantiate a Phone object using the class definition from Activity 1.
  • Do not provide any values for brand, model, color, or price.
  • What do you think will be printed when you try to print $phone->price?
  • Why?
Answer / solution

Nothing is printed except the newlines because no price was set.

Activity 4

  • Instantiate a Phone object.
  • What do you think will be printed when you try to print a property that doesn't exist, such as $phone->size?
Answer / solution

An error message is printed:

Warning: Undefined property: Phone::$size

Class methods

Methods are functions that are part of a class definition - just like properties are variables or constants that are part of a class definition. 

Methods need the same access modifiers that properties do: public, private, or protected. If you don't specify one, public will be assumed. Learn more in the section on access modifiers.

Example without return value

Let's update the Phone class and add a method to call another phone number:

Code
<?php

class Phone {

 public $brand;
 public $color;
 public $model;
 public $price;


 public function callNumber($number) {

   // Code for calling a number goes here.

 }
}
Code
<?php

$myphone = new Phone();
$phone->callNumber('+32478123456');

Example with return value

Code
<?php

class Phone {

  public $brand;
  public $color;
  public $model;
  public $price;


  public function callNumber($number) {

    // Code for calling a number goes here.

  }

  public function countUnreadMessages() {

    // Code for counting the  message goes here.
    // Let's set it to 12 for this demonstration.
    return 12;

  }

}
$myphone = new Phone();
print $phone->countUnreadMessages();

As you can see, a method really behaves like any other function.

Variable scope

The scope of variables is limited to the method in which they are declared. In other words, variables declared in one method are not visible in other methods nor outside the class.

The same goes for class properties: a class method cannot directly access any of its properties. For a method to access its properties, you need to use the $this keyword.

The $this keyword

You have learned that you can invoke an object's method or access an object's property by using the object operator (->) on that object:

Code
<?php

$object->nameOfMethod();
print $object->nameOfProperty;

But what do you do when you want to write a method that uses another method of the same class, or accesses a property of the same class?

Example: a method that prints the phone's brand name.

You could TRY the following, but it would be WRONG:

Code
<?php

// This is INCORRECT and results in a WARNING or ERROR depending on your PHP settings.
class Phone {

 public $brand;

 public function printBrand() {
   print $brand;
 }
}
Code
<?php

$myphone = new Phone();
$myphone->printBrand();

In the above example, the statement print $brand will result in a warning or error because $brand refers to a variable named "brand" (which does not exist), not a property named "brand" (which does exist).

This is why the $this keyword exists: it's a pseudo-variable that means "the current object".

Here's how you use $this:

Code
<?php

class Phone {

  public $brand;

  public function printBrand() {
    print $this->brand;
  }
}

$myphone = new Phone();
$myphone->brand = 'Samsung';
$myphone->printBrand();

What you're telling PHP is that whenever any Phone object is instantiated and someone invokes the printBrand() method on that object, the method will take that object's $brand value and print it.

Activity 5

  • What do you think will be printed in this example? 
  • Why? 

     

class Phone {

  public $brand

  public function printBrand() {
    $brand = 'Apple';
    print $this->brand;
  }
}

$myphone = new Phone();
$myphone->brand = 'Samsung';
$myphone->printBrand();
Answer / solution

Samsung is printed:

  • We instantiate a Phone object
  • We set the brand property on the Phone object to Samsung
  • We call the printBrand() method on the Phone object.


The fact that the printBrand() method contains a statement that introduces a local variable $brand and sets it to Apple has no effect on the statement that prints the object's brand property.

$brand and $this->brand are different things that happen to have the same name.


In this example, the statement $brand = 'Apple' is completely useless as we don't do anything with the local $brand variable after creating it and assigning 'Apple' to it.


It's a bit confusing at first, but again: the brand property and the local $brand variable inside the printBrand() method are not the same thing, even though they're both called "brand". 

You've seen an example of accessing a property from within a class. Now let's look at how one method invokes another method inside a class:

Code
<?php

class Phone {

  public function calculateBatteryLife() {
    // Code to do the actual calculation goes here. 
    //We'll assume 100% to keep it simple for now.
    return 100;
  }

  public function printBatteryLife() {
    $battery_life = $this->calculateBatteryLife();
    print $battery_life;
  }
}

$myphone = new Phone();
$myphone->printBatteryLife();

Explanation

When invoked, printBatteryLife() invokes calculateBatteryLife() to get the actual battery life, and then prints that value.

We certainly could have kept all this code in a single method, but it's a good practice to create several smaller methods that each have their own responsibility and do one thing, rather than mixing it all together in one long method. 

More on this later.

Class constants

Constants are similar to variables: you can assign a value to them, you can print them, and can pass them to functions or methods as parameters.

However:  constants are immutable: once you've assigned a value to a constant, their value can no longer change while the code is being executed. 

Attempting to assign a value to a constant that is already defined will result in an error.

Note:

  • Constant names are not prefixed with a $.
  • Constant names always use UPPER CASE notation by convention


Basic const example

Code
<?php

// Define const.
const MEMORY_LIMIT = 64;

// Use const.
print(MEMORY_LIMIT);

Class const example

Class properties are typically variables, but you can use consts too:

Code
<?php

class Circle {

  public const PI = 3.14;
  public float $radius;

  public function __construct(float $radius) {
    $this->radius = $radius;
  }

  public function calculateCircumference(): float {
    return 2 * self::PI * $this->radius;
  }

}

$mycircle = new Circle(5);
print("Circumference: {$mycircle->calculateCircumference()}" . PHP_EOL);
print ($mycircle::PI);

$this vs self::

Accessing constant properties uses different syntax than addressing variable properties:

Code
<?php

// Accessing a variable property from inside a class definition
print ($this->name_of_variable);
// Accessing a const property from inside a class definition
print (self::NAME_OF_CONST);
// Accessing a variable property from outside a class definition
print ($myobject->name_of_variable);
// Accessing a const property from outside a class definition
print ($myobject::NAME_OF_CONST);

→ When you want to access a class const, you need to use the self keyword in combination with the so-called "double colon" scope resolution operator: self::NAME_OF_CONST

Summary

  • You can use a class definition to instantiate objects of that class / type.
  • New objects are instantiated using the new keyword.
  • Objects typically represent state (data) and behavior (functionality).
  • Class properties contain data; class methods provide functionality.
  • The $this pseudo-variable and self keyword reference the current object.
  • Use the :: scope resolution operator to access class consts.