<?phpclassUser{publicstring$name;publicstring$username;publicstring$password;// one can define static class members and methodspublicstaticstring$STATIC_MEMBER="SOME_CONSTANT";// the constructor (return type is by default User, // and not declared); constructor not strictly needed if// class member assignment not requiredpublicfunction__construct(string$name,string$username,string$password){$this->name=$name;$this->username=$username;$this->password=$password;}// PHP 8 provides a more concise way to define constructors;// note this does not require public field declarations// listed above either (approach below is known as property promotion):// public function __construct(public string $name, // public string $username, public string $password) {}// note that class methods are public be default // (other scopes PHP 5+ are protected and private, similar to Java)functionconfirmPassword(string$password):bool{return$this->password==$password;}functiongreeting():string{return"Parent hello {$this->name}\n";}}// grab the staticecho"Static class member: ".User::$STATIC_MEMBER."\n";$userOne=newUser("Joe Bloggs","joebloggs","tempPassword");$isConfirmed=$userOne->confirmPassword("randomPassword")?"True":"False";echo"Password is correct? $isConfirmed\n";echo$userOne->greeting();
Inheritance
<?phprequire'23. Classes.php';classAdminextendsUser{publicfunction__construct(publicstring$name,publicstring$username,publicstring$password,publicstring$role){}// this overrides the parent method; note the signature must be identicalpublicfunctiongreeting():string{return"Admin hello ".$this->name."\n";}}$newAdminUser=newAdmin("Jane Bloggs","admin","adminPassword","admin");echo"New admin with role: $newAdminUser->role\n";$adminPasswordConfirmed=$newAdminUser->confirmPassword("adminPassword")?"True":"False";echo"New admin password is adminPassword: $adminPasswordConfirmed\n";classNonAdminextendsUser{publicfunction__construct(publicstring$name,publicstring$username,publicstring$password,publicstring$role){}// this overrides the parent method; note the signature must be identicalpublicfunctiongreeting():string{return"Non-admin hello ".$this->name."\n";}}$users=[newAdmin("Mr and Mrs Admin","admin","adminPassword","admin"),newNonAdmin("Mr and Mrs Non-admin","nonadmin","nonAdminPassword","non-admin"),newUser("Mr and Mrs User","user","tempPassword")];functionintroducePolymorphic(User$user):void{// use the base class call, and let PHP decide // which to call based on the instanceecho$user->greeting();}// exhibit polymorphismforeach($usersas$user){introducePolymorphic($user);}
Class member visibility
<?phpclassBankDetails{privatefloat$balance=0;// don't have to use getClassMember or // setClassMember as method names// recognised as a getter by the IDE // (can be replaced by a property hook)publicfunctiongetBalance():float{return$this->balance;}publicfunctiondeposit(float$balance):void{if($balance<0){$this->balance=0;}else{$this->balance+=$balance;}}publicfunctionwithdraw(float$amount):bool{if($amount>0&&$this->balance>=$amount){$this->balance-=$amount;returntrue;}returnfalse;}}$bankAccountDetails=newBankDetails();echo"Balance: ".$bankAccountDetails->getBalance().PHP_EOL;echo"Depositing amount -300".PHP_EOL;$bankAccountDetails->deposit(-300);echo"Balance: ".$bankAccountDetails->getBalance().PHP_EOL;echo"Depositing amount 400".PHP_EOL;$bankAccountDetails->deposit(400);echo"Balance: ".$bankAccountDetails->getBalance().PHP_EOL;echo"Withdrawing amount -300".PHP_EOL;$bankAccountDetails->withdraw(-300);echo"Balance: ".$bankAccountDetails->getBalance().PHP_EOL;echo"Withdrawing amount 500".PHP_EOL;$bankAccountDetails->withdraw(500);echo"Balance: ".$bankAccountDetails->getBalance().PHP_EOL;echo"Withdrawing amount 200".PHP_EOL;$bankAccountDetails->withdraw(200);echo"Balance: ".$bankAccountDetails->getBalance().PHP_EOL;
Singletons
<?phpclassDBConnection{privatestatic$instance=null;privatefunction__construct(){}publicstaticfunctiongetInstance(){// can use this if DBConnection is never // going to be extended with overridden methods// if (null === DBConnection::$instance) {// DBConnection::$instance = new DBConnection();// }// if one were to extend this class, then one // should use late static binding to instantiate and get// access to the child (overridden) methods; // overall this is the preferred approachif(null===static::$instance){static::$instance=newstatic();}returnDBConnection::$instance;}}var_dump(DBConnection::getInstance());
Interfaces and abstract classes
<?phpinterfaceHttpMethods{// must all be publicfunctionsendGetRequest(string$url):int;functionsendPostRequest(string$url):int;functionsendPutRequest(string$url):int;functionsendDeleteRequest(string$url):int;// class members are only supported by // PHP 8.4.0+; alternatively, set up class members// with an abstract class that declares class members}// abstract classes need not implement // interface methods, unlike concrete classesabstractclassHttpMethodsStartupServiceimplementsHttpMethods{// applying property promotionpublicfunction__construct(protectedstring$apiKey){}abstractprotectedfunctionvalidateApiKey():bool;}// this concrete class must implement // all methods not implemented by the abstract class;// note that apiKey is not accessible to // classes that extend HttpMethodsServiceclassHttpMethodsServiceextendsHttpMethodsStartupService{functionsendGetRequest(string$url):int{if($this->validateApiKey()){echo"GET $url with API key: $this->apiKey\n";return200;}return301;}functionsendPostRequest(string$url,string$method='POST'):int{if($this->validateApiKey()){echo"POST $url with API key: $this->apiKey\n";return200;}return301;}functionsendPutRequest(string$url,string$method='PUT'):int{if($this->validateApiKey()){echo"PUT $url with API key: $this->apiKey\n";return200;}return301;}functionsendDeleteRequest(string$url,string$method='DELETE'):int{if($this->validateApiKey()){echo"DELETE $url with API key: $this->apiKey\n";return200;}return301;}protectedfunctionvalidateApiKey():bool{if(null===$this->apiKey){thrownewException("API Key not set");}return!($this->apiKey=="");}}$service=newHttpMethodsService("Bearer somethingCryptic");$service->sendGetRequest("https://api.exmaple.com/param");
Traits
<?php// Traits group together helper methods and allow classes to share // methods there and only then,// without resorting to inheritance; Traits cannot be instantiatedtraitCustomLogger{functionlog(string$message):void{echo$message.PHP_EOL;}}classTestTrait{// get access to TestTrait methodsuseCustomLogger;function__construct(publicstring$message){}functioncommit():void{$this->log("Commiting ".$this->message." to the database...");}}$testEntity=newTestTrait("TestEntity instance");$testEntity->commit();
Final and readonly (PHP 8.1+)
<?php// final classes cannot be extendedfinalclassNonInheritableClass{functiononlyHere(string|int|float$message){echo"Here and only here: $message\n";}}classSomeReadOnlyMethods{readonlyprotectedstring$key;// one can also use promoted class members with the readonly keywordpublicfunction__construct(){$this->key='AB434KKFJmnvp';}finalfunctionreadOnlyMethod(){echo"This method cannot be overridden\n";}functionprintReadOnlyMember(){echo"This class member cannot be changed at runtime: $this->key\n";}}$nonInheritableClass=newNonInheritableClass();$nonInheritableClass->onlyHere(SomeReadOnlyMethods::class);$someReadOnlyMember=newSomeReadOnlyMethods();$someReadOnlyMember->printReadOnlyMember();$someReadOnlyMember->readOnlyMethod();
Enumerations
<?php// enum with values assigned (string or int allowed)enumDaysOfTheWeek:string{caseMonday='Monday';caseTuesday='Tuesday';caseWednesday='Wednesday';caseThursday='Thursday';caseFriday='Friday';caseSaturday='Saturday';caseSunday='Sunday';}enumDaysOfTheWeekNumerical:int{caseMonday=2;caseTuesday=3;caseWednesday=4;caseThursday=5;caseFriday=6;caseSATURDAY=7;caseSUNDAY=8;}$todayIsMonday=DaysOfTheWeek::Monday;if($todayIsMonday===DaysOfTheWeek::Monday){echo'Today\'s string enum value is '.DaysOfTheWeek::Monday->value.PHP_EOL;echo'Today\'s string enum name is '.DaysOfTheWeek::Monday->name.PHP_EOL;}$todayIsSunday=DaysOfTheWeekNumerical::SUNDAY;if($todayIsSunday===DaysOfTheWeekNumerical::SUNDAY){echo'Today\'s int enum value is '.DaysOfTheWeekNumerical::SUNDAY->value.PHP_EOL;echo'Today\'s int enum name is '.DaysOfTheWeekNumerical::SUNDAY->name.PHP_EOL;}