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
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.
Пример бр. 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()
?>
Пример бр. 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)
?>
Напомена: Properties cannot be declared final, only classes and methods may be declared as final.
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
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.
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
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.
<?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
?>
@someone
@thomas
Decorating a finalized class is not possible. The decorator that's mentioned is incomplete. There's a fundamental flaw in it. Look:
<?php
//copy'n'paste your FooBar, Foo definition
$f = new Foo;
$fd = new FooDecorator($f);
var_dump($fd instanceof $f); //FALSE
var_dump(is_a($fd, 'Foo')); //FALSE
fooFoo($fd); //E_RECOVERABLE_ERROR here !!!;
?>
What you've created is just an object that happens to have the same methods(a duck type). But if in the client code someone makes decision based on the type of your passed decorator they'll make incorrect decision - or to be more precise not the one that you, the author of the 'decorator' wants them to make.
FYI that's the correct implementation based on GoF:
<?php
class Foo
{
public method doFoo()
{
// do something useful and return a result
}
}
//decorator must inherit the interface(the methods, type info etc.) //of the decorated class by *extending* it.
class FooDecorator extends Foo
{
private $foo;
public function __construct(Foo $foo)
{
$this->foo = $foo;
}
public function doFoo()
{
$result = $this->foo->doFoo();
// ... customize result ...
return $result;
}
}
function fooFoo(Foo $f) {}
$f = new Foo;
$fd = new FooDecorator($f);
var_dump($fd instanceof $f); //true
fooFoo($fd); //no E_RECOVERABLE_ERROR here;
?>
I haven't come across any legitimate use of a finalizing class/method and I personally think that 'final' is has no much use and is just a copy'n'pasted from Java into PHP. The keyword makes code difficult to test. If you have to create a test double from a finalized class because you'll need create a derived type to shadow the methods you don't care about. If one of them is finalized you've already lost.
@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;
}
}
?>
"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 :
<?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($className, false)) return;
if (class_exists($className, false)) {
$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 B {
public static $X;
private static function __init() {
echo 'B', "\n";
self::$X = array(1, 2);
}
}
class A {
public static $Y;
private static function __init() {
echo 'A', "\n";
self::$Y = array(3, 4);
}
}
?>
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.
?>
Please, please, please never use this keyword anywhere in your code. By using it you are saying that you somehow magically know that your class or method is perfect and will suit every possible use of the class API you're defining and that no one will ever need to do so much as add some data checking before calling parent:: on the method.
This is never true and will never be true, so let the poor programmer that needs to extend your code do so.
If you want to have "final" in your code then you don't understand OOP.
Hopefully this will be removed in some future version of the language.