Traits facilitate code reuse in PHP by providing a simple way to define functionality and reuse those functionalities when we need it.
Trait is a group of methods(and properties) that can be inserted and used in a class.
As we can use multiple traits in a class, so it compensates for the lack of multiple inheritance nature of PHP.
Traits do not comply with the “is-a” nature of inheritance, so traits do not follow the true strict inheritance behavior.
NOTE
Think of using a Trait as copy-pasting code & functionality.
When we use a Trait in a class, just imagine that it has copied the code from the Trait(s), and pasted it in the class.
After including(using) a trait in a class, then methods(and properties) behave as if those are defined in the class itself.
Traits Capability
Let’s see what Traits can and can not do-
Traits can do
Traits can not do
NOTE
Before PHP version 8.2, it was not possible to define a constant in a trait. If a constant is defined in an older version then an error with the following message would be generated-
Fatal Error: Traits can not have constants…..
NOTE
We have a full comparison of the Interface, Abstract Class, and trait.
Check the link below for a full comparison-
Trait Declaration
// Trait declaration
trait SampleTraitOne {
// properties and methods here
}
PHPUsing Traits
To use the trait in a class just use the keyword “use” and then the trait name, like below-
// Trait usage
class SampleClassOne {
// Use trait in the class
use SampleTraitOne;
// class properties and methods here
}
PHPWe can use one or more traits in a class-
// Trait usage
class SampleClassOne {
// Use multiple traits
use SampleTraitOne, SampleTraitTwo, TraitThree;
// Declare trait use in multiple line
use TraitFour;
// class properties and methods here
}
PHPNOTE
Traits can not be instantiated by itself. It has to be used in a class, to use its functionality.
Let’s check what happens when we print the class name inside a trait-
<?php
trait MyTrait {
public function printClassName(): void {
echo 'Class name (inside trait): ' . __CLASS__ . PHP_EOL;
}
public function printTraitName(): void {
echo 'Trait name: ' . __TRAIT__ . PHP_EOL;
}
}
class BigBoxOne {
use MyTrait;
}
class BigBoxTwo {
use MyTrait;
}
// Demo
$bigBoxOne = new BigBoxOne();
$bigBoxTwo = new BigBoxTwo();
$bigBoxOne->printClassName();
$bigBoxOne->printTraitName();
$bigBoxTwo->printClassName();
$bigBoxTwo->printTraitName();
PHPOutput:
It will print the class name where the trait is being used-
Class name (inside trait): BigBoxOne
Trait name: MyTrait
Class name (inside trait): BigBoxTwo
Trait name: MyTrait
PlaintextUsing Method from Trait
To use a method from a trait, make sure the trait is being used in the class.
Then call the method as if, it is declared inside the class.
<?php
// Trait definition
trait FirstTrait {
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
use FirstTrait;
}
// Demo
$bigBoxObj = new BigBoxClassExample();
// Call method from object, which is defined in trait
$bigBoxObj->myFunc();
PHPNOTE
If you call the trait method inside any method of the class, then add a check with the function “method_exists()“.
class BigBoxClassExample {
use FirstTrait;
public function myClassFunc(): void {
if (method_exists($this, 'myFunc')) {
$this->myFunc();
}
// Some other code here
}
}
This will make sure that the script does not throw errors in case the trait is not added in the class.
Declaring Abstract Method in Trait
We can add an abstraction function in the trait-
<?php
// Trait definition
trait FirstTrait {
const BIG_BOX_CONST = "Some Special Value";
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
// Declare an abstract function
abstract public function myAbsFunc(): string;
}
// Class definition
class BigBoxClassExample {
use FirstTrait;
// Add the definition of the abstract function
public function myAbsFunc(): string
{
return "some string result generated in the abstract method" . PHP_EOL;
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
echo $bigBoxObj->myAbsFunc();
PHPOutput:
myFunc in the First Trait
some string result generated in the abstract method
PlaintextWARNING
Using abstract method is helpful when some part of the implementation will depend on the class(that is using the trait). So we can define those parts in the class, in the abstract class definition.
If the definition of the abstract method is not added in the class then we get an error like below-
PHP Fatal error: Class BigBoxClassExample contains 1 abstract method
and must therefore be declared abstract or implement the remaining methods
(BigBoxClassExample::myAbsFunc) in test.php on line 16
Declaring Static Method in Trait
We can define a static method in the trait. It will behave as if the static method is defined in the class, that is using the trait.
<?php
// Trait definition
trait FirstTrait {
const BIG_BOX_CONST = "Some Special Value";
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
// Declare a static function
public static function myStaticFunc(): string {
return "some string result generated in the static method" . PHP_EOL;
}
}
// Class definition
class BigBoxClassExample {
use FirstTrait;
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
// Use the static method
echo $bigBoxObj::myStaticFunc();
PHPOutput:
myFunc in the First Trait
some string result generated in the static method
PlaintextDeclaring Final Method in Trait
We can define a method as final in the trait, but it will still be overridden in the class using the trait-
<?php
// Trait definition
trait FirstTrait {
final public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
}
// Class definition
class BigBoxClassExample {
use FirstTrait;
public function myFunc(): void {
echo "myFunc in the class" . PHP_EOL;
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
PHPOutput:
myFunc in the class
PlaintextUnlike a parent class. When we define a method as final in the parent and try to redefine it in the child, we get an error-
<?php
class BigBoxParent {
final public function myFunc(): void {
echo "myFunc in the Parent" . PHP_EOL;
}
}
class ChildOne extends BigBoxParent{
public function myFunc(): void {
echo "myFunc in the child" . PHP_EOL;
}
}
// Demo
$child = new ChildOne();
$child->myFunc();
PHPOutput:
PHP Fatal error: Cannot override final method BigBoxParent::myFunc() in ..../sample.php on line 10
PlaintextSo when we extend the class that is using trait, and then try to redefine the method in the child, then we get an error-
<?php
// Trait definition
trait FirstTrait
{
final public function myFunc(): void
{
echo "myFunc in the First Trait" . PHP_EOL;
}
}
// Parent Class definition
class BigBoxClassExample
{
use FirstTrait;
}
// Child class definition
class BigBoxChild extends BigBoxClassExample
{
// Try to override a final method
public function myFunc(): void
{
echo "myFunc in the child class" . PHP_EOL;
}
}
// Demo
$bigBoxObj = new BigBoxChild();
$bigBoxObj->myFunc();
PHPOutput:
PHP Fatal error: Cannot override final method BigBoxClassExample::myFunc() in .../sample.php on line 22
PlaintextMethod Precedence
When a class uses a trait, and the same method is defined in the trait and the class(or in the parent class), then-
Here is the precedence in a nutshell-
Class Method > Trait Method > Inherited Method( from Parent)
Case #1: Same function in Trait and Class
If a function with the same name is defined in the trait and the class using it, then the definition in the class gets higher priority–
<?php
// Trait definition
trait BigBoxTraitExample {
public function myFunc(): void {
echo "myFunc in the trait" . PHP_EOL;
}
}
// Class definition
class BigBoxClassExample {
use BigBoxTraitExample;
// Same function defined in the class and trait
public function myFunc(): void
{
echo "myFunc in the class" . PHP_EOL;
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
PHPOutput:
myFunc in the class
PlaintextCase #2: Same function in Trait and Parent Class
If a function with same name is defined in the trait, and the parent class of the class using the trait.
And the function is not defined in the class it self, then the definition in trait gets higher priority than the function definition of the parent class–
<?php
// Trait definition
trait BigBoxTraitExample {
public function myFunc(): void {
echo "myFunc in the trait" . PHP_EOL;
}
}
// Parent class
class BigBoxParent {
public function myFunc(): void {
echo "myFunc in the parent" . PHP_EOL;
}
}
// Our class
class BigBoxClassExample extends BigBoxParent {
use BigBoxTraitExample;
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
PHPOutput:
myFunc in the trait
PlaintextCase #3: Redefine the Function with a Different Signature
We can redefine a method, in the class with different signature. We can change the main signature, return type, even visibility-
<?php
// Trait definition
trait FirstTrait {
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
use FirstTrait;
private function myFunc(): string {
return "myFunc in the class" . PHP_EOL;
}
public function sampleFunc() {
echo $this->myFunc();
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->sampleFunc();
PHPOutput:
myFunc in the class
PlaintextConflict Resolution
Let’s see what happens when we have a function with the same name in multiple traits, and we want to use those multiple traits in a class-
Problem
Here we have a function with the name “myFunc” in 2 traits “FirstTrait” and “SecondTrait“.
And we are using “FirstTrait” and “SecondTrait” in the class “BigBoxClassExample“.
This will generate an error.
<?php
// Trait definition
trait FirstTrait {
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
}
trait SecondTrait {
public function myFunc(): void {
echo "myFunc in the Second Trait" . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
use FirstTrait, SecondTrait;
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
PHPOutput:
When we run the code, we get an error like the one below-
PHP Fatal error: Trait method SecondTrait::myFunc has not been applied as BigBoxClassExample::myFunc, because of collision with FirstTrait::myFunc in ...sample.php on line 17
In this case we can do one of the following-
Case #1: Resolve Conflict
While adding the “use” statement for the traits, for one of the traits we can use “insteadof” to give this priority. Like-
HighPriotiryTraitName::functionNameHere insteadof LowPriorityTraitName
PHPCheck the example below-
<?php
// Trait definition
trait FirstTrait {
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
}
trait SecondTrait {
public function myFunc(): void {
echo "myFunc in the Second Trait" . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
use FirstTrait;
// Prefer myFunc from SecondTrait
use SecondTrait {
SecondTrait::myFunc insteadof FirstTrait;
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
PHPOutput:
myFunc in the Second Trait
PlaintextCase #2: Resolve Conflict and Use Both Methods
If we want to use both of the method definitions, then-
<?php
// Trait definition
trait FirstTrait {
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
}
trait SecondTrait {
public function myFunc(): void {
echo "myFunc in the Second Trait" . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
use FirstTrait {
// Give myFunc from FirstTrait a different name
FirstTrait::myFunc as someChangedFuncName;
}
// Prefer myFunc from SecondTrait
use SecondTrait{
SecondTrait::myFunc insteadof FirstTrait;
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
// Calling with the changed name
$bigBoxObj->someChangedFuncName();
PHPOutput:
myFunc in the Second Trait
myFunc in the First Trait
PlaintextUsing Trait Property
We can define properties inside the trait. If a property is defined in the trait, and the trait is used in a class, then-
<?php
// Trait definition
trait FirstTrait {
protected string $someTraitProp = "some val of prop- 3456";
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
echo "value of \$someTraitProp: " . $this->someTraitProp . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
use FirstTrait;
public function myClassFunc(): void {
echo 'Value of property defined in trait is: ' . $this->someTraitProp . PHP_EOL;
}
// Utility function for debugging purpose
// Check properties
public function printPropInfo(): void
{
$classRef = new ReflectionClass($this);
$props = $classRef->getProperties();
foreach ($props as $prop) {
$output = "Prop: {$prop->getName()} | Type: {$prop->getType()} | Value: {$prop->getValue($this)} | ";
if ($prop->isPublic()) {
$output .= "Visibility: Public";
}
if ($prop->isPrivate()) {
$output .= "Visibility: Private";
}
if ($prop->isProtected()) {
$output .= "Visibility: Protected";
}
echo $output . PHP_EOL;
}
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
$bigBoxObj->myClassFunc();
$bigBoxObj->printPropInfo();
PHPOutput:
myFunc in the First Trait
value of $someTraitProp: some val of prop- 3456
Value of property defined in trait is: some val of prop- 3456
Prop: someTraitProp | Type: string | Value: some val of prop- 3456 | Visibility: Protected
PlaintextNOTE
If you call the trait property inside the class, then add a check with the function “property_exists()“.
class BigBoxClassExample {
use FirstTrait;
public function myClassFunc(): void {
if (property_exists($this, 'someTraitProp')) {
// Safe the use the trait property here
$totalValue = $this->someTraitProp * 80 / 100;
}
// Some other code here
}
}
PHPThis will make sure that the script does not throw errors in case the trait is not added in the class.
Redeclare Trait Property in Class
If there is a property defined in a trait, and we want to redeclare the same property in the class using the trait, then it is a little tricky. Follow the information below-
NOTE
If we redeclare a property(already defined in a trait) in a class(that is using the trait), then the definition needs to be exactly the same.
Property visibility, type, and value need to be fully compatible(exactly the same). Otherwise, we will get an error.
Let’s take a look at a few cases of this property redeclaration-
Case #1: Redeclare property with different value [Error]
The value of the property in the trait and in the class needs to be exactly the same. Else we will get an error-
<?php
// Trait definition
trait FirstTrait {
protected string $someTraitProp = "some val of prop- 3456";
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
echo "value of \$someTraitProp: " . $this->someTraitProp . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
protected string $someTraitProp;
// Use SecondTrait only (which in turn uses FirstTrait)
use FirstTrait;
public function myClassFunc(): void {
echo 'Value of property defined in trait is: ' . $this->someTraitProp . PHP_EOL;
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
$bigBoxObj->myClassFunc();
PHPOutput:
PHP Fatal error: BigBoxClassExample and FirstTrait define the same property ($someTraitProp) in the composition of BigBoxClassExample. However, the definition differs and is considered incompatible. Class was composed in .../sample.php on line 23
PlaintextCase #2: Redeclare property with different visibility [Error]
The visibility(access modifier) needs to be the same for the property in the trait and in the class, else we will get error-
<?php
// Trait definition
trait FirstTrait {
protected string $someTraitProp = "some val of prop- 3456";
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
echo "value of \$someTraitProp: " . $this->someTraitProp . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
protected string $someTraitProp = "some different value";
use FirstTrait;
public function myClassFunc(): void {
echo 'Value of property defined in trait is: ' . $this->someTraitProp . PHP_EOL;
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
$bigBoxObj->myClassFunc();
PHPOutput:
PHP Fatal error: BigBoxClassExample and FirstTrait
define the same property ($someTraitProp)
in the composition of BigBoxClassExample.
However, the definition differs
and is considered incompatible.
Class was composed in .../sample.php on line 23
PlaintextCase #3: Change Property Value Later
Once the property is defined in the class(with exact same definition), then we can change the value at any point of the execution later-
<?php
// Trait definition
trait FirstTrait {
protected string $someTraitProp = "some val of prop- 3456";
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
echo "value of \$someTraitProp: " . $this->someTraitProp . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
protected string $someTraitProp = "some val of prop- 3456";
use FirstTrait;
public function myClassFunc(): void {
$this->someTraitProp = "value changed in the class";
echo 'Value of property defined in trait is: ' . $this->someTraitProp . PHP_EOL;
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
$bigBoxObj->myClassFunc();
PHPOutput:
myFunc in the First Trait
value of $someTraitProp: some val of prop- 3456
Value of property defined in trait is: value changed in the class
PlaintextUsing Static Property in Trait
We can declare a static property in the trait, and a class can use the static property-
<?php
trait BigBoxTrait
{
protected static int $totalCount = 0;
function getTraitTotalCount(): int
{
return self::$totalCount;
}
}
class BigBoxOne
{
use BigBoxTrait;
public function getTotalCount(): int
{
return self::$totalCount;
}
public function setTotalCount(int $count): void
{
self::$totalCount = $count;
}
}
// Demo
$bigBoxOne = new BigBoxOne();
echo 'Total count in BigBoxOne: ' . $bigBoxOne->getTotalCount() . PHP_EOL;
// Change total count from BigBoxOne
$bigBoxOne->setTotalCount(999);
echo "After change" . PHP_EOL;
echo 'Total count in BigBoxOne: ' . $bigBoxOne->getTotalCount() . PHP_EOL;
PHPOutput:
Total count in BigBoxOne:
After change
Total count in BigBoxOne: 999
PlaintextNOTE
If a trait is used in multiple class, then static properties are not shared between those classes.
Unlike we have in a parent class. If 2 classes extend the same parent class and the parent has a static property, then the same static property is shared between the parent and child.
For clarity, check the following example with parent and child classes-
The static property is shared between the parent and all children, so changing the static value from anywhere will change it for the parent and all children.
<?php
class BigBoxParent {
protected static int $totalCount = 0;
function getParentTotalCount(): int {
return self::$totalCount;
}
}
class BigBoxOne extends BigBoxParent{
function getTotalCount(): int {
return self::$totalCount;
}
function setTotalCount(int $count): void {
self::$totalCount = $count;
}
}
class BigBoxTwo extends BigBoxParent{
function getTotalCount(): int {
return self::$totalCount;
}
}
// Demo
$bigBoxParent = new BigBoxParent();
$bigBoxOne = new BigBoxOne();
$bigBoxTwo = new BigBoxTwo();
echo 'Total count in BigBoxParent: ' . $bigBoxParent->getParentTotalCount() . PHP_EOL;
echo 'Total count in BigBoxOne: ' . $bigBoxOne->getTotalCount() . PHP_EOL;
echo 'Total count in BigBoxTwo: ' . $bigBoxTwo->getTotalCount() . PHP_EOL;
// Change total count from BigBoxOne
$bigBoxOne->setTotalCount(999);
echo "After change" . PHP_EOL;
echo 'Total count in BigBoxParent: ' . $bigBoxParent->getParentTotalCount() . PHP_EOL;
echo 'Total count in BigBoxOne: ' . $bigBoxOne->getTotalCount() . PHP_EOL;
echo 'Total count in BigBoxTwo: ' . $bigBoxTwo->getTotalCount() . PHP_EOL;
PHPOutput:
Total count in BigBoxParent:
Total count in BigBoxOne:
Total count in BigBoxTwo:
After change
Total count in BigBoxParent: 999
Total count in BigBoxOne: 999
Total count in BigBoxTwo: 999
PlaintextNow let’s try the same thing with trait
The static property is not shared between the classes using the trait, so changing the static value from anywhere will not affect others.
<?php
trait BigBoxTrait
{
protected static int $totalCount = 0;
function getTraitTotalCount(): int
{
return self::$totalCount;
}
}
class BigBoxOne
{
use BigBoxTrait;
function getTotalCount(): int
{
return self::$totalCount;
}
function setTotalCount(int $count): void
{
self::$totalCount = $count;
}
}
class BigBoxTwo
{
use BigBoxTrait;
function getTotalCount(): int
{
return self::$totalCount;
}
}
// Demo
$bigBoxOne = new BigBoxOne();
$bigBoxTwo = new BigBoxTwo();
echo 'Total count in BigBoxOne: ' . $bigBoxOne->getTotalCount() . PHP_EOL;
echo 'Total count in BigBoxTwo: ' . $bigBoxTwo->getTotalCount() . PHP_EOL;
// Change total count from BigBoxOne
$bigBoxOne->setTotalCount(999);
echo "After change" . PHP_EOL;
echo 'Total count in BigBoxOne: ' . $bigBoxOne->getTotalCount() . PHP_EOL;
echo 'Total count in BigBoxTwo: ' . $bigBoxTwo->getTotalCount() . PHP_EOL;
PHPOutput:
Total count in BigBoxOne:
Total count in BigBoxTwo:
After change
Total count in BigBoxOne: 999
Total count in BigBoxTwo:
PlaintextTrait Composition(from other Traits)
We can use one or more other Traits inside a trait. We can include the taits by “use” keyword-
<?php
// Trait definition
trait FirstTrait {
public function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
}
// Second trait definition
trait SecondTrait {
// Use FirstTrait in SecondTrait
use FirstTrait;
public function mySecondFunc(): void {
echo "mySecondFunc in the Second Trait" . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
// Use SecondTrait only (which in turn uses FirstTrait)
use SecondTrait;
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
$bigBoxObj->mySecondFunc();
PHPOutput:
myFunc in the First Trait
mySecondFunc in the Second Trait
PlaintextChange Visibility
We can change the visibility of a method of a trait, while using it in a class.
Problem
Say we have a trait with a private method. and we want to call the method from the class object-
<?php
// Trait definition
trait FirstTrait {
private function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
use FirstTrait;
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
PHPOutput:
We will get an error as the methods private, and we are invoking it from the class object.
PHP Fatal error: Uncaught Error: Call to private method BigBoxClassExample::myFunc() from global scope in .../sample.php:31
Stack trace:
#0 {main}
thrown in .../sample.php on line 31
PlaintextChange Visibility of the Method
We can change the visibility of the method while including the trait in a class, using the “as” keyword and then the access modifier(public/protected/public).
In the following example we have changed the visibility of “myFunc” method to “public“-
<?php
// Trait definition
trait FirstTrait {
private function myFunc(): void {
echo "myFunc in the First Trait" . PHP_EOL;
}
}
// Our class
class BigBoxClassExample {
use FirstTrait {
// Change visibility of the method from private to public
FirstTrait::myFunc as public;
}
}
// Demo
$bigBoxObj = new BigBoxClassExample();
$bigBoxObj->myFunc();
PHPOutput:
myFunc in the First Trait
PlaintextExample
<?php
// Define trait for NOS
trait Nos
{
private bool $usingNos = false;
public function addNos(): void
{
$this->usingNos = true;
echo "Adding NOS" . PHP_EOL;
}
}
// Define class Car
class Car
{
// Use trait Nos in the class
use Nos;
public function __construct(
private int $wheel,
private int $engine,
private int $seat,
private int $door,
private bool $interior
) {
}
public function start(): void
{
echo "Car started" . PHP_EOL;
}
public function stop(): void
{
echo "Car Stopped" . PHP_EOL;
}
public function repair(): void
{
echo "Repair Car" . PHP_EOL;
}
// Utility function for debugging purpose
public function printInfo(): void
{
$carRef = new ReflectionClass($this);
$props = $carRef->getProperties();
foreach ($props as $prop) {
echo "Prop: {$prop->getName()} | Type: {$prop->getType()} | Value: {$prop->getValue($this)}" . PHP_EOL;
}
}
}
$car = new Car(4, 2, 4, 4, true);
$car->start();
$car->stop();
$car->repair();
$car->addNos();
$car->printInfo();
PHPOutput:
Car started
Car Stopped
Repair Car
Adding NOS
Prop: wheel | Type: int | Value: 4
Prop: engine | Type: int | Value: 2
Prop: seat | Type: int | Value: 4
Prop: door | Type: int | Value: 4
Prop: interior | Type: bool | Value: 1
Prop: usingNos | Type: bool | Value: 1
Plaintext