Skip to content

Latest commit

 

History

History
1235 lines (868 loc) · 24.1 KB

File metadata and controls

1235 lines (868 loc) · 24.1 KB

⌂ Home ▲ Previous: Fibers ▼ Next: Class members

Classes

Definition

In programming, a class is a syntactic entity structure used to create objects.  The capabilities of a class differ between programming languages, but generally the shared aspects consist of state (variables) and behavior (methods) that are each either associated with a particular object or with all objects of that class.

Object state can differ between each instance of the class whereas the class state is shared by all of them. The object methods include access to the object state (via an implicit or explicit parameter that references the object) whereas class methods do not.

If the language supports inheritance, a class can be defined based on another class with all of its state and behavior plus additional state and behavior that further specializes the class. The specialized class is a sub-class, and the class it is based on is its superclass.

In purely object-oriented programming languages, such as Java and C#, all classes might be part of an inheritance tree such that the root class is Object, meaning all objects instances are of Object or implicitly extend Object, which is called a top type.

-- Wikipedia

Description

PHP includes a complete object model. Some of its features are: visibility, abstract and final classes and methods, additional magic methods, interfaces, and cloning.

PHP treats objects in the same way as references or handles, meaning that each variable contains an object reference rather than a copy of the entire object.

-- PHP Reference

Example: Class

<?php

class SomeClass
{
    public $someProperty = 64;
    private $otherProperty = 'broccoli';

    function someMethod()
    {
        return $this->otherProperty;
    }

    function otherMethod($someArgument)
    {
        $this->otherProperty = $someArgument;
    }
}

$someObject = new SomeClass();

print($someObject->someProperty . PHP_EOL);
print($someObject->someMethod() . PHP_EOL . PHP_EOL);

$someObject->someProperty = 128;
$someObject->otherMethod('cauliflower');

print($someObject->someProperty . PHP_EOL);
print($someObject->someMethod() . PHP_EOL . PHP_EOL);

Result (PHP 8.4):

64
broccoli

128
cauliflower

Source code: Example

Class definition

class keyword

Basic class definitions begin with the keyword class, followed by a class name, followed by a pair of curly braces which enclose the definitions of the properties and methods belonging to the class.

The class name can be any valid label, provided it is not a PHP reserved word. As of PHP 8.4.0, using a single underscore _ as a class name is deprecated. A valid class name starts with a letter or underscore, followed by any number of letters, numbers, or underscores. As a regular expression, it would be expressed thus: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$.

A class may contain its own constants, variables (called properties), and functions (called methods).

Example: Simple class definition

<?php
class SimpleClass
{
    // property declaration
    public $var = 'a default value';

    // method declaration
    public function displayVar() {
        echo $this->var;
    }
}
?>

-- PHP Reference

Example: Class definiton

<?php

class SomeClass
{
    public $someProperty;
    public $otherProperty;

    function someMethod()
    {
        return "{$this->someProperty} & {$this->otherProperty}";
    }
}

class OtherClass
{
    public int $someNumber;
    public float $someValue;
    public string $someText;

    function someMethod(int $number, float $value): string
    {
        $this->someNumber = $number;
        $this->someValue = $value;
        $this->someText = (string) ($number * $value);

        return $this->someText;
    }

    function otherMethod(): float
    {
        return $this->someNumber * $this->someValue;
    }
}

$someObject = new SomeClass();
$someObject->someProperty = 256;
$someObject->otherProperty = 'tomato';
$result = $someObject->someMethod();

print($result . PHP_EOL);

$otherObject = new OtherClass();
$result = $otherObject->someMethod(3, 1.5);

print($result . PHP_EOL);
print($otherObject->otherMethod() . PHP_EOL);

Result (PHP 8.4):

256 & tomato
4.5
4.5

Source code: Example

Class instantiation

new keyword

To create an instance of a class, the new keyword must be used. An object will always be created unless the object has a constructor defined that throws an exception on error. Classes should be defined before instantiation (and in some cases this is a requirement).

-- PHP Reference

Note:

If there are no arguments to be passed to the class's constructor, parentheses after the class name may be omitted.

-- PHP Reference

Example: Class instantiation

<?php

class SomeClass
{
}

class OtherClass
{
    private(set) string $someProperty;

    function __construct(string $someValue)
    {
        $this->someProperty = $someValue;
    }
}

$someObject = new SomeClass;

print("Some object\n");
var_dump($someObject);
print(PHP_EOL);

$otherObject = new SomeClass();

print("Other object\n");
var_dump($otherObject);
print(PHP_EOL);

$anotherObject = new OtherClass('onion');

print("Another object\n");
var_dump($anotherObject);
print("Initialied property: {$anotherObject->someProperty}\n");
print(PHP_EOL);

Result (PHP 8.4):

Some object
object(SomeClass)#1 (0) {
}

Other object
object(SomeClass)#2 (0) {
}

Another object
object(OtherClass)#3 (1) {
  ["someProperty"]=>
  string(5) "onion"
}
Initialied property: onion

Source code: Example

If a variable containing a string with the name of a class is used with new, a new instance of that class will be created. If the class is in a namespace, its fully qualified name must be used when doing this.

Example: Creating an instance

<?php
class SimpleClass {
}

$instance = new SimpleClass();
var_dump($instance);

// This can also be done with a variable:
$className = 'SimpleClass';
$instance = new $className(); // new SimpleClass()
var_dump($instance);
?>

-- PHP Reference

Example: Class instantiation from a string

<?php

class SomeClass
{
}

class OtherClass
{
}

class AnotherClass
{
}

const CLASS_NAME = 'SomeClass';
$someObject = new (CLASS_NAME)();

print("Some object\n");
var_dump($someObject);
print(PHP_EOL);

$className = 'OtherClass';
$otherObject = new $className();

print("Other object\n");
var_dump($otherObject);
print(PHP_EOL);

$anotherObject = new ('An' . $className)();

print("Another object\n");
var_dump($anotherObject);
print(PHP_EOL);

Result (PHP 8.4):

Some object
object(SomeClass)#1 (0) {
}

Other object
object(OtherClass)#2 (0) {
}

Another object
object(AnotherClass)#3 (0) {
}

Source code: Example

As of PHP 8.0.0, using new with arbitrary expressions is supported. This allows more complex instantiation if the expression produces a string. The expressions must be wrapped in parentheses.

Example: Creating an instance using an arbitrary expression

In the given example we show multiple examples of valid arbitrary expressions that produce a class name. This shows a call to a function, string concatenation, and the ::class constant.

<?php

class ClassA extends \stdClass {}
class ClassB extends \stdClass {}
class ClassC extends ClassB {}
class ClassD extends ClassA {}

function getSomeClass(): string
{
    return 'ClassA';
}

var_dump(new (getSomeClass()));
var_dump(new ('Class' . 'B'));
var_dump(new ('Class' . 'C'));
var_dump(new (ClassD::class));
?>

Output of the above example in PHP 8:

object(ClassA)#1 (0) {
}
object(ClassB)#1 (0) {
}
object(ClassC)#1 (0) {
}
object(ClassD)#1 (0) {
}

-- PHP Reference

Example: Class instantiation from and expression

<?php

class SomeClass
{
}

class OtherClass
{
}

class AnotherClass
{
}

function giveClassName(): string
{
    return 'OtherClass';
}

$someObject = new ('Some' . 'Class')();

print("Some object\n");
var_dump($someObject);
print(PHP_EOL);

$otherObject = new (giveClassName())();

print("Other object\n");
var_dump($otherObject);
print(PHP_EOL);

$anotherObject = new ('An' . giveClassName())();

print("Another object\n");
var_dump($anotherObject);
print(PHP_EOL);

Result (PHP 8.4):

Some object
object(SomeClass)#1 (0) {
}

Other object
object(OtherClass)#2 (0) {
}

Another object
object(AnotherClass)#3 (0) {
}

Source code: Example

In the class context, it is possible to create a new object by new self and new parent.

[Also from new static. -- KK]

-- PHP Reference

Example: Class instantiation from static, self and parent keywords

<?php

class BaseClass
{
    static function createStatic()
    {
        return new static();
    }

    static function createSelf()
    {
        return new self();
    }
}

class DerivedClass extends BaseClass
{
    static function createParent()
    {
        return new parent();
    }
}

$fromBaseStaticObject = BaseClass::createStatic();

print("From base static\n");
var_dump($fromBaseStaticObject);
print(PHP_EOL);

$fromBaseSelfObject = BaseClass::createSelf();

print("From base self\n");
var_dump($fromBaseSelfObject);
print(PHP_EOL);

$fromDerivedStatic = DerivedClass::createStatic();

print("From derived static\n");
var_dump($fromDerivedStatic);
print(PHP_EOL);

$fromDerivedSelf = DerivedClass::createSelf();

print("From derived self\n");
var_dump($fromDerivedSelf);
print(PHP_EOL);

$fromDerivedParent = DerivedClass::createParent();

print("From derived parent\n");
var_dump($fromDerivedParent);
print(PHP_EOL);

Result (PHP 8.4):

From base static
object(BaseClass)#1 (0) {
}

From base self
object(BaseClass)#2 (0) {
}

From derived static
object(DerivedClass)#3 (0) {
}

From derived self
object(BaseClass)#4 (0) {
}

From derived parent
object(BaseClass)#5 (0) {
}

Source code: Example

It's possible to create instances of an object in a couple of ways:

Example: Creating new objects

<?php

class Test
{
    public static function getNew()
    {
        return new static();
    }
}

class Child extends Test {}

$obj1 = new Test(); // By the class name
$obj2 = new $obj1(); // Through the variable containing an object
var_dump($obj1 !== $obj2);

$obj3 = Test::getNew(); // By the class method
var_dump($obj3 instanceof Test);

$obj4 = Child::getNew(); // Through a child class method
var_dump($obj4 instanceof Child);

?>

The above example will output:

bool(true)
bool(true)
bool(true)

-- PHP Reference

Example: Class instantiation by factory method

<?php

class SomeClass
{
    static function create()
    {
        return new static();
    }

    private function __construct()
    {
    }
}

$someObject = SomeClass::create();

print("Object:\n");
var_dump($someObject);
print(PHP_EOL);

Result (PHP 8.4):

Object:
object(SomeClass)#1 (0) {
}

Source code: Example

Example: Class instantiation ways

<?php

class SomeClass
{
    public static function constructByStatic()
    {
        return new static();
    }

    public static function constructBySelf()
    {
        return new self();
    }
}

class OtherClass extends SomeClass
{
    static function constructByParent()
    {
        return new parent();
    }
}

$someObject = new SomeClass();

print("# From the explicit class name:\n\n");
print('Created object class: '. get_class($someObject) . PHP_EOL . PHP_EOL);

$fromObject = new $someObject;

print("# From an object of the particular class:\n\n");
print(
    'Original object class: ' . get_class($someObject) . PHP_EOL
    . 'Created object class: ' . get_class($fromObject) . PHP_EOL
    . PHP_EOL
);
print("Equal:\n");
var_dump($fromObject == $someObject);
print("Identical:\n");
var_dump($fromObject === $someObject);
print(PHP_EOL);

$className = 'SomeClass';
$fromString = new $className();

print("# From a string containing the particular class name:\n\n");
print('Created object class: '. get_class($fromString) . PHP_EOL . PHP_EOL);

function getClassName(): string
{
    return 'SomeClass';
}

$fromExpression = new (getClassName());

print("# From an expression which value contains the particular class name:\n\n");
print('Created object class: '. get_class($fromExpression) . PHP_EOL . PHP_EOL);

$fromClassNameResolution = new (SomeClass::class);

print("# From the particular class name resolution:\n\n");
print('Created object class: '. get_class($fromClassNameResolution) . PHP_EOL . PHP_EOL);

$byStatic = SomeClass::constructByStatic();
$bySelf = SomeClass::constructBySelf();
$byParent = OtherClass::constructByParent();

print("# From a factory method of the particular class:\n\n");
print(
    'By static: ' . get_class($byStatic) . PHP_EOL
    . 'By self: ' . get_class($bySelf) . PHP_EOL
    . 'By parent: ' . get_class($byParent) . PHP_EOL
    . PHP_EOL
);

Result (PHP 8.4):

# From the explicit class name:

Created object class: SomeClass

# From an object of the particular class:

Original object class: SomeClass
Created object class: SomeClass

Equal:
bool(true)
Identical:
bool(false)

# From a string containing the particular class name:

Created object class: SomeClass

# From an expression which value contains the particular class name:

Created object class: SomeClass

# From the particular class name resolution:

Created object class: SomeClass

# From a factory method of the particular class:

By static: SomeClass
By self: SomeClass
By parent: SomeClass

Source code: Example

When assigning an already created instance of a class to a new variable, the new variable will access the same instance as the object that was assigned. This behaviour is the same when passing instances to a function. A copy of an already created object can be made by cloning it.

Example: Object assignment

<?php
class SimpleClass {
    public string $var;
}

$instance = new SimpleClass();

$assigned   =  $instance;
$reference  =& $instance;

$instance->var = '$assigned will have this value';

$instance = null; // $instance and $reference become null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

The above example will output:

NULL
NULL
object(SimpleClass)#1 (1) {
   ["var"]=>
     string(30) "$assigned will have this value"
}

-- PHP Reference

Example: Object assigning to the variable, passing to the function and returning by the function

<?php

class SomeClass
{
}

class OtherClass
{
}

class AnotherClass
{
}

function receivingFunction(object $objectArgument)
{
    print("As function argument\n");
    var_dump($objectArgument);
    print(PHP_EOL);
}

function returningFunction()
{
    return new AnotherClass();
}

$someObject = new SomeClass();

print("As a variable\n");
var_dump($someObject);
print(PHP_EOL);

receivingFunction(new OtherClass);

print("As a function result\n");
var_dump(returningFunction());
print(PHP_EOL);

Result (PHP 8.4):

As a variable
object(SomeClass)#1 (0) {
}

As function argument
object(OtherClass)#2 (0) {
}

As a function result
object(AnotherClass)#2 (0) {
}

Source code: Example

Example: Object access

<?php

class SomeClass
{
    public $someProperty = 'betroot';
}

$someObject = new SomeClass();

print("Object:\n");
print_r($someObject);
print(PHP_EOL);

$someVariable = $someObject;

print("Variable:\n");
print_r($someVariable);
print(PHP_EOL);

$someReference = &$someObject;

print("Reference:\n");
print_r($someObject);
print(PHP_EOL);

$someClone = clone $someObject;

print("Clone:\n");
print_r($someClone);
print(PHP_EOL);

print("Change of variable\n\n");

$someVariable->someProperty = 'carrot';

print("Variable:\n");
print_r($someVariable);
print(PHP_EOL);

print("Object:\n");
print_r($someObject);
print(PHP_EOL);

print("Change of reference\n\n");

$someReference->someProperty = 'parsley';

print("Reference:\n");
print_r($someObject);
print(PHP_EOL);

print("Object:\n");
print_r($someObject);
print(PHP_EOL);

print("Change of clone\n\n");

$someClone->someProperty = 'radish';

print("Clone:\n");
print_r($someClone);
print(PHP_EOL);

print("Object:\n");
print_r($someObject);
print(PHP_EOL);

Result (PHP 8.4):

Object:
SomeClass Object
(
    [someProperty] => betroot
)

Variable:
SomeClass Object
(
    [someProperty] => betroot
)

Reference:
SomeClass Object
(
    [someProperty] => betroot
)

Clone:
SomeClass Object
(
    [someProperty] => betroot
)

Change of variable

Variable:
SomeClass Object
(
    [someProperty] => carrot
)

Object:
SomeClass Object
(
    [someProperty] => carrot
)

Change of reference

Reference:
SomeClass Object
(
    [someProperty] => parsley
)

Object:
SomeClass Object
(
    [someProperty] => parsley
)

Change of clone

Clone:
SomeClass Object
(
    [someProperty] => radish
)

Object:
SomeClass Object
(
    [someProperty] => parsley
)

Source code: Example

It is possible to access a member of a newly created object in a single expression:

Example: Access member of newly created object

<?php
echo (new DateTime())->format('Y'), PHP_EOL;

// surrounding parentheses are optional as of PHP 8.4.0
echo new DateTime()->format('Y'), PHP_EOL;
?>

The above example will output something similar to:

2025
2025

Note: Prior to PHP 7.1, the arguments are not evaluated if there is no constructor function defined.

-- PHP Reference

Example: Class instantiation and immediate instance member access

<?php

class SomeClass
{
    public $someProperty = 'watermelon';
    private $otherProperty = 'pumpkin';

    function someMethod()
    {
        return $this->otherProperty;
    }
}

$value = (new SomeClass())->someProperty;

print($value . PHP_EOL);

$value = (new SomeClass())->someMethod();

print($value . PHP_EOL);

Result (PHP 8.4):

watermelon
pumpkin

Source code: Example

Readonly classes

readonly modifier

As of PHP 8.2.0, a class can be marked with the readonly modifier. Marking a class as readonly will add the readonly modifier to every declared property, and prevent the creation of dynamic properties. Moreover, it is impossible to add support for them by using the AllowDynamicProperties attribute. Attempting to do so will trigger a compile-time error.

<?php
#[\AllowDynamicProperties]
readonly class Foo {
}

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
?>

As neither untyped nor static properties can be marked with the readonly modifier, readonly classes cannot declare them either:

<?php
readonly class Foo
{
    public $bar;
}

// Fatal error: Readonly property Foo::$bar must have type
?>
<?php
readonly class Foo
{
    public static int $bar;
}

// Fatal error: Readonly class Foo cannot declare static properties
?>

-- PHP Reference

Example: Readonly class

<?php

readonly class SomeReadonlyClass
{
    public int $someProperty;
    public string $otherProperty;

    public function __construct()
    {
        $this->someProperty = 10;
        $this->otherProperty = 'magenta';
    }
}

$someReadonlyObject = new SomeReadonlyClass();

print("Some property: {$someReadonlyObject->someProperty}\n");
print("Some readonly property: {$someReadonlyObject->otherProperty}\n");

Result (PHP 8.4):

Some property: 10
Some readonly property: magenta

Source code: Example

A readonly class can be extended if, and only if, the child class is also a readonly class.

-- PHP Reference

Example: Readonly class inheritance

<?php

readonly class SomeReadonlyClass
{
    public int $someProperty;
    public string $otherProperty;

    public function __construct()
    {
        $this->someProperty = 10;
        $this->otherProperty = 'magenta';
    }
}

readonly class SomeDerivedClass extends SomeReadonlyClass
{
}

$someReadonlyObject = new SomeDerivedClass();

print("Some property: {$someReadonlyObject->someProperty}\n");
print("Some readonly property: {$someReadonlyObject->otherProperty}\n");

Result (PHP 8.4):

Some property: 10
Some readonly property: magenta

Source code: Example

Class name resolution

::class

The class keyword is also used for class name resolution. To obtain the fully qualified name of a class ClassName use ClassName::class. This is particularly useful with namespaced classes.

Example: Class name resolution

<?php
namespace NS {
    class ClassName {
    }

    echo ClassName::class;
}
?>

The above example will output:

NS\ClassName

Note:

The class name resolution using ::class is a compile time transformation. That means at the time the class name string is created no autoloading has happened yet. As a consequence, class names are expanded even if the class does not exist. No error is issued in that case.

Example: Missing class name resolution

<?php
print Does\Not\Exist::class;
?>

The above example will output:

Does\Not\Exist

As of PHP 8.0.0, ::class may also be used on objects. This resolution happens at runtime, not compile time. Its effect is the same as calling get_class() on the object.

Example: Object name resolution

<?php
namespace NS {
    class ClassName {
    }

    $c = new ClassName();
    print $c::class;
}
?>

The above example will output:

NS\ClassName

-- PHP Reference

Example: Class name resolution

<?php

namespace SomeNamespace;

class SomeClass
{
}

print(SomeClass::class . PHP_EOL);

Result (PHP 8.4):

SomeNamespace\SomeClass

Source code: Example

▵ Up ⌂ Home ▲ Previous: Fibers ▼ Next: Class members