Final Keyword

PHP 5 introduces the final keyword, which prevents child classes from overriding a method 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";
   }

   
// Here it doesn't matter if you specify the function as final or not
   
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)
?>

Note: Properties cannot be declared final, only classes and methods may be declared as final.

Коментарии

Note that you cannot ovverride final methods even if they are defined as private in parent class.
Thus, the following example:
<?php
class parentClass {
    final private function 
someMethod() { }
}
class 
childClass extends parentClass {
    private function 
someMethod() { }
}
?>
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.
2007-03-22 03:39:07
http://php5.kiev.ua/manual/ru/language.oop5.final.html
<?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
?>
2007-10-31 01:13:48
http://php5.kiev.ua/manual/ru/language.oop5.final.html
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
2008-12-05 04:45:58
http://php5.kiev.ua/manual/ru/language.oop5.final.html
Note for Java developers: the 'final' keyword is not used for class constants in PHP. We use the keyword 'const'.

language.oop5.constants
2009-07-17 17:20:16
http://php5.kiev.ua/manual/ru/language.oop5.final.html
Автор:
"Note for Java developers: the 'final' keyword is not used for class constants in PHP. We use the keyword 'const'."

language.oop5.constants

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 :

<?php
class Bar {...}
class 
Foo {
  public static 
$FOOBAR;

  static function 
__init() {
    static 
$init false;
    if (
$init) throw new Exception('Constants were already initialized');
   
self::$FOOBAR = new Bar();
   
$init true;
  }
}
Foo::__init();
?>
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 : 

<?php
function __autoload($className) { 
  ... require 
the file where the class is ...
  if (
interface_exists($classNamefalse)) return;
  if (
class_exists($classNamefalse)) {
   
$rc = new ReflectionClass($className); 
    if (!
$rc->hasMethod('__init')) return;
   
$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:
<?php
class {
 public static 
$X;
 private static function 
__init() {
   echo 
'B'"\n"
   
self::$X = array(12);
 }
}
class 
{
  public static 
$Y;
  private static function 
__init() {
    echo 
'A'"\n"
   
self::$Y = array(34);
  }
}
?>
test.php:
<?php
function __autoload($n) {
  if (
$n == 'A' || $n == 'B') require 'test2.php';
  ... do 
our __init() trick ...
}
var_dump(B::$X); // shows B, then array(2) (1, 2)
var_dump(A::$Y); // shows NULL.
?>
2010-08-31 16:37:50
http://php5.kiev.ua/manual/ru/language.oop5.final.html
Автор:
The behaviour of FINAL is not as serious as you may think. A little explample:
<?php
class {
     final private function 
method(){}     
}

class 
extends {
    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.
2010-09-28 10:06:20
http://php5.kiev.ua/manual/ru/language.oop5.final.html
@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.

<?php
final class Foo
{
    public 
method doFoo()
    {
       
// do something useful and return a result
   
}
}

final class 
FooDecorator
{
    private 
$foo;
   
    public function 
__construct(Foo $foo)
    {
       
$this->foo $foo;
    }
   
    public function 
doFoo()
    {
         
$result $this->foo->doFoo();
         
// ... customize result ...
         
return $result;
    }
}
?>
2014-01-05 00:40:54
http://php5.kiev.ua/manual/ru/language.oop5.final.html
imo good to know:
<?php
class BaseClass
{
    protected static 
$var 'i belong to BaseClass';

    public static function 
test()
    {
        echo 
'<hr>'.
           
'i am `'.__METHOD__.'()` and this is my var: `'.self::$var.'`<br>';
    }
    public static function 
changeVar($val)
    {
       
self::$var $val;
        echo 
'<hr>'.
           
'i am `'.__METHOD__.'()` and i just changed my $var to: `'.self::$var.'`<br>';
    }
    final public static function 
dontCopyMe($val)
    {
       
self::$var $val;
        echo 
'<hr>'.
           
'i am `'.__METHOD__.'()` and i just changed my $var to: `'.self::$var.'`<br>';
    }
}

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

    public static function 
test()
    {
        echo 
'<hr>'.
           
'i am `'.__METHOD__.'()` and this is my var: `'.self::$var.'`<br>'.
           
'and this is my parent var: `'.parent::$var.'`';
    }
    public static function 
changeVar($val)
    {
       
self::$var $val;
        echo 
'<hr>'.
           
'i am `'.__METHOD__.'()` and i just changed my $var to: `'.self::$var.'`<br>'.
           
'but the parent $var is still: `'.parent::$var.'`';
    }
    public static function 
dontCopyMe($val// Fatal error: Cannot override final method BaseClass::dontCopyMe() in ...
   
{
       
self::$var $val;
        echo 
'<hr>'.
           
'i am `'.__METHOD__.'()` and i just changed my $var to: `'.self::$var.'`<br>';
    }
}

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 ...
?>
2014-05-12 21:02:59
http://php5.kiev.ua/manual/ru/language.oop5.final.html
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):

<?php
interface FooInterface
{
}

class 
Foo implements FooInterface
{
    const 
BAR 1;

    public function 
__construct()
    {
    }
}

interface 
BazInterface
{
    public function 
getFooBar();
}

// This class cannot be unit tested in isolation because the actual class Foo must also be loaded to get the value of Foo::BAR
class Baz implements BazInterface
{
    private 
$foo;

    public function 
__construct(FooInterface $foo)
    {
       
$this->foo $foo;
    }

    public function 
getFooBar()
    {
        return 
Foo::BAR;
    }

}

$foo = new Foo();
$baz = new Baz($foo);
$bar $baz->getFooBar();
?>

Loose coupling example (eliminated constant usage):

<?php
interface FooInterface
{
    public function 
bar();
}

class 
Foo implements FooInterface
{
    public function 
__construct()
    {
    }

    final public function 
bar()
    {
        return 
1;
    }
}

interface 
BazInterface
{
    public function 
getFooBar();
}

// This class can be unit tested in isolation because class Foo does not need to be loaded by mocking FooInterface and calling the final bar method.
class Baz implements BazInterface
{
    private 
$foo;

    public function 
__construct(FooInterface $foo)
    {
       
$this->foo $foo;
    }

    public function 
getFooBar()
    {
        return 
$this->foo->bar();
    }

}

$foo = new Foo();
$baz = new Baz($foo);
$bar $baz->getFooBar();
?>
2014-06-03 22:24:56
http://php5.kiev.ua/manual/ru/language.oop5.final.html
Автор:
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.
2023-05-03 16:56:36
http://php5.kiev.ua/manual/ru/language.oop5.final.html
Автор:
When desiring a special class structure finalizing magic methods maybe helpful.

<?php

abstract class 
  final public function 
__construnct(){ echo "A"; } 
}

class 
extends {
  public function 
__construct(){ echo "B"; }
}

$b = new B(); // outputs: PHP Fatal error:  Cannot override final method a\A::__construct()

?>
2024-08-08 22:14:37
http://php5.kiev.ua/manual/ru/language.oop5.final.html

    Поддержать сайт на родительском проекте КГБ