PHP: Hypertext Preprocessor (original) (raw)

Final Keyword

The final keyword prevents child classes from overriding a method, property, or constant by prefixing the definition with final. If the class itself is being defined final then it cannot be extended.

Example #1 Final methods example

`<?php
class BaseClass {
public function test() {
echo "BaseClass::test() called\n";
}

final public function

moreTesting() {
echo "BaseClass::moreTesting() called\n";
}
}

class

ChildClass extends BaseClass {
public function moreTesting() {
echo "ChildClass::moreTesting() called\n";
}
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
?>`

Example #2 Final class example

`<?php
final class BaseClass {
public function test() {
echo "BaseClass::test() called\n";
}// As the class is already final, the final keyword is redundant
final public function moreTesting() {
echo "BaseClass::moreTesting() called\n";
}
}

class

ChildClass extends BaseClass {
}
// Results in Fatal error: Class ChildClass may not inherit from final class (BaseClass)
?>`

Example #3 Final property example as of PHP 8.4.0

`<?php
class BaseClass {
final protected string $test;
}

class

ChildClass extends BaseClass {
public string $test;
}
// Results in Fatal error: Cannot override final property BaseClass::$test
?>`

Example #4 Final constants example as of PHP 8.1.0

`<?php
class Foo
{
final public const X = "foo";
}

class

Bar extends Foo
{
public const X = "bar";
}// Fatal error: Bar::X cannot override final constant Foo::X
?>`

Note: As of PHP 8.0.0, private methods may not be declared final except for the constructor.

Note: A property that is declared private(set) is implicitly final.

Found A Problem?

jriddy at gmail dot com

15 years ago

penartur at yandex dot ru

18 years ago

`Note that you cannot ovverride final methods even if they are defined as private in parent class.
Thus, the following example:

dies with error "Fatal error: Cannot override final method parentClass::someMethod() in ***.php on line 7"

Such behaviour looks slight unexpected because in child class we cannot know, which private methods exists in a parent class and vice versa.

So, remember that if you defined a private final method, you cannot place method with the same name in child class.

`

Rumour

2 years ago

Class constants CAN be “finalised” since PHP8.1. To partly contradict to the most popular user contribution, that was written a long time ago, they were still absolutely right.

someone dot else at elsewhere dot net

11 years ago

`@thomas at somewhere dot com

The 'final' keyword is extremely useful. Inheritance is also useful, but can be abused and becomes problematic in large applications. If you ever come across a finalized class or method that you wish to extend, write a decorator instead.

this−>foo=this->foo = this>foo=foo; } public function doFoo() { result=result = result=this->foo->doFoo(); // ... customize result ... return $result; } } ?>

`

slorenzo at clug dot org dot ve

17 years ago

<?php class parentClass { public function someMethod() { } } class childClass extends parentClass { public final function someMethod() { } //override parent function }$class = new childClass; $class->someMethod(); //call the override function in chield class ?>

mattsch at gmail dot com

10 years ago

`You can use final methods to replace class constants. The reason for this is you cannot unit test a class constant used in another class in isolation because you cannot mock a constant. Final methods allow you to have the same functionality as a constant while keeping your code loosely coupled.

Tight coupling example (bad to use constants):

this−>foo=this->foo = this>foo=foo; } public function getFooBar() { return Foo::BAR; } } $foo = new Foo(); baz=newBaz(baz = new Baz(baz=newBaz(foo); bar=bar = bar=baz->getFooBar(); ?>

Loose coupling example (eliminated constant usage):

this−>foo=this->foo = this>foo=foo; } public function getFooBar() { return $this->foo->bar(); } } $foo = new Foo(); baz=newBaz(baz = new Baz(baz=newBaz(foo); bar=bar = bar=baz->getFooBar(); ?>

`

cottton at i-stats dot net

10 years ago

`` imo good to know:
<?php
class BaseClass
{
protected static $var = 'i belong to BaseClass';

public static function

test()
{
echo '


'.
'i am '.__METHOD__.'() and this is my var: '.self::$var.'
';
}
public static function changeVar($val)
{
self::$var = $val;
echo '
'.
'i am '.__METHOD__.'() and i just changed my varto:‘′.self::var to: &#x27;.self::</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6151em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">t</span><span class="mord mathnormal">o</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9463em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord">‘</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord">.</span><span class="mord mathnormal">se</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span></span></span></span>var.'
';
}
final public static function dontCopyMe($val)
{
self::$var = $val;
echo '
'.
'i am '.__METHOD__.'() and i just changed my varto:‘′.self::var to: &#x27;.self::</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6151em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">t</span><span class="mord mathnormal">o</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9463em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord">‘</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord">.</span><span class="mord mathnormal">se</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span></span></span></span>var.'
';
}
}

class

ChildClass extends BaseClass
{
protected static $var = 'i belong to ChildClass';

public static function

test()
{
echo '


'.
'i am '.__METHOD__.'() and this is my var: '.self::$var.'
'.
'and this is my parent var: '.parent::$var.'';
}
public static function changeVar($val)
{
self::$var = $val;
echo '
'.
'i am '.__METHOD__.'() and i just changed my varto:‘′.self::var to: &#x27;.self::</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6151em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">t</span><span class="mord mathnormal">o</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9463em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord">‘</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord">.</span><span class="mord mathnormal">se</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span></span></span></span>var.'
'.
'but the parent varisstill:‘′.parent::var is still: &#x27;.parent::</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">i</span><span class="mord mathnormal">ss</span><span class="mord mathnormal">t</span><span class="mord mathnormal">i</span><span class="mord mathnormal" style="margin-right:0.01968em;">ll</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9463em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord">‘</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord">.</span><span class="mord mathnormal">p</span><span class="mord mathnormal">a</span><span class="mord mathnormal">re</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span></span></span></span>var.'';
}
public static function dontCopyMe($val) // Fatal error: Cannot override final method BaseClass::dontCopyMe() in ...
{
self::$var = $val;
echo '
'.
'i am '.__METHOD__.'() and i just changed my varto:‘′.self::var to: &#x27;.self::</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6151em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">t</span><span class="mord mathnormal">o</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9463em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord">‘</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord">.</span><span class="mord mathnormal">se</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">::</span></span></span></span>var.'
';
}
}BaseClass::test(); // i am BaseClass::test() and this is my var: i belong to BaseClass
ChildClass::test(); // i am ChildClass::test() and this is my var: i belong to ChildClass
// and this is my parent var: i belong to BaseClass
ChildClass::changeVar('something new'); // i am ChildClass::changeVar() and i just changed my $var to: something new
// but the parent $var is still: i belong to BaseClass
BaseClass::changeVar('something different'); // i am BaseClass::changeVar() and i just changed my $var to: something different
BaseClass::dontCopyMe('a text'); // i am BaseClass::dontCopyMe() and i just changed my $var to: a text
ChildClass::dontCopyMe('a text'); // Fatal error: Cannot override final method BaseClass::dontCopyMe() in ...
?> ``

santoshjoshi2003 at yahoo dot co dot in

16 years ago

`The use of final keyword is just like that occurs in Java
In java final has three uses

  1. prevent class Inheritance
  2. prevent method overriding or redifination of
    method in subclass
  3. and to declare constants
    But the third point seems to be missing from the PHP
    I guess, as i am a java developer Currently gaining competence in PHP`

Anonymous

14 years ago

`The behaviour of FINAL is not as serious as you may think. A little explample:
<?php
class A {
final private function method(){}
}

class

B extends A {
private function method(){}
}
?>

Normally you would expect some of the following will happen:

  • An error that final and private keyword cannot be used together
  • No error as the private visibility says, that a method/var/etc. is only visible within the same class

But what happens is PHP is a little curios: "Cannot override final method A::method()"

So its possible to deny method names in subclasses! Don't know if this is a good behavior, but maybe its useful for your purpose.

`

Anonymous

9 months ago

`When desiring a special class structure finalizing magic methods maybe helpful.

`

Baldurien

14 years ago

`"Note for Java developers: the 'final' keyword is not used for class constants in PHP. We use the keyword 'const'."

http://php.net/manual/en/language.oop5.constants.php

This is more or less true, regardless of the fact that constant (being defined at class level or not) in PHP are only scalar (int, string, etc) while in Java they may be pure object (ex: java.awat.Color.BLACK). The only possible solution of having such kind of constant is :

That said, perhaps it is useless unless PHP automatically calls the __init() method.

However, one alternative that could be done in certain case is this :

rc=newReflectionClass(rc = new ReflectionClass(rc=newReflectionClass(
className); if (!$rc->hasMethod('__init')) return; m=m = m=rc->getMethod('__init'); if (!($m->isStatic() && $m->isPrivate())) { throw new Exception($className . ' __init() method must be private and static !'); } $m->invoke(null); return; } throw new Exception('Class or interface not found ' . $className); } ?>

This can only work when one class is defined per file, since we are assured that __autoload() will be called to load the file containing the class.

eg:

test2.php:

test.php:

`