php scope resolution operator - php

Why does this return a "strict standard" notice?:
'Strict Standards: Non-static method main::i() should not be called statically in...'
class main
{
public function __construct()
{
echo "in main class";
}
public function i()
{
echo "i in main";
}
}
class secondary extends main
{
public static function tom()
{
parent::i();
}
}
secondary::tom();
I am legally calling a static method which contains a call to a non static method in a parent class.

The notice is telling you should not call a non static method within a static method.
You could check the method i(), if $this doesn't appear in that method, you may consider change i() to static method.

You've already answered the question yourself - while you're calling tom() statically (which is fine), i() is not static.
Being non-static i() assumes that you have an instance of the object, and therefore could be trying to access properties or perform other actions which require an instance. As such it shouldn't be called statically, not even from within a static method in a child class. Consider for example the following slight change to your code:
class main
{
var something = 0;
public function __construct()
{
echo "in main class";
}
public function i()
{
$this->something++;
echo "i in main";
}
}
class secondary extends main
{
public static function tom()
{
parent::i();
}
}
secondary::tom();
It's a strict warning - meaning you can choose to ignore it if you want to - but it's informing you that what you're doing is not generally good practice and you should probably rethink your approach.

class main
{
public function __construct()
{
echo "in main class";
}
public static function i()
{
echo "i in main";
}
}
class secondary extends main
{
public static function tom()
{
parent::i();
}
}
secondary::tom();
Is what it should look like, notice I have converted the function i(); to a static, which then can legally be called by parent::i();
But performing:
public static function tom()
{
$this->i();
}
Will return:
Fatal error: Using $this when not in object context
So your bet is to go fully static, or not static.
A resolution:
class main
{
public function __construct()
{
echo "in main class";
}
public function i()
{
echo "i in main";
}
}
class secondary extends main
{
public function tom()
{
$this->i();
}
}
$Class = new secondary();
$Class->tom();

Related

Within a class : Access to a function A from a function B

I have a problem which is probably not for most of you.
Sorry if it is obvious for you...
This is my code :
class Bat
{
public function test()
{
echo"ici";
exit();
}
public function test2()
{
$this->test();
}
}
In my controller:
bat::test2();
i have an error:
Exception information: Message: Method "test" does not exist and was
not trapped in __call()
Bat::test2 refers to a static function. So you have to declare it static.
class Bat
{
public static function test()
{
echo"ici";
exit();
}
// You can call me from outside using 'Bar::test2()'
public static function test2()
{
// Call the static function 'test' in our own class
// $this is not defined as we are not in an instance context, but in a class context
self::test();
}
}
Bat::test2();
Else, you need an instance of Bat and call the function on that instance:
$myBat = new Bat();
$myBat->test2();

Can I make a function child of another Class without extends Class?

My Class is independant from another Class.
Inside my Class, a function is doing the same but refined job as a function in another Class. Can I use parent:: function_in_another_class() and get my function join that parent funciton's job flow?
No.
In PHP you can only extend from none or one class. As you write both classes are independent to each other, there is no information where to find the one or the other class.
But what you're looking for is probably this:
class A
{
function myFunction() {}
}
class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
public function myFunction()
{
$this->a->myFunction();
}
}
If any class method already doing the same thing why would you bother call join it?
You can not do it. If you want the same job flow best way to do is to instantiate the other class and invoke that very same method. Thats why we use OOP.
See the example,
interface Fable()
{
public function f();
}
class OtherClass implements Fable
{
public function f()
{
// job flow
}
}
class MyClass
{
private $fable;
public function __construct(Fable $f)
{
$this->fable = $f;
}
public function method1($args){
return $this->fable->f($args);
}
}
If the current class is a child of another class, yes, you can. parent references to the parent class.
From php.net:
<?php
class A {
function example() {
echo "I am A::example() and provide basic functionality.<br />\n";
}
}
class B extends A {
function example() {
echo "I am B::example() and provide additional functionality.<br />\n";
parent::example();
}
}
$b = new B;
// This will call B::example(), which will in turn call A::example().
$b->example();
?>
The best you can do here is to extend Class B from Class A
Class B extends Class A
But, you can also:
class ClassA {
function do_something($args) {
// Do something
}
}
class ClassB {
function do_something_inclassA($args) {
classA::do_something($args);
}
}
Important: calling classa::do_something(); is a static call, in other words with error reporting E_STRICT you will get a static notice warning because function do_something() is not static function do_something()
Also, calling this function statically (i.e. classa::do_something()) means that class a's function cannot refer to $this within it

PHP5 static methods inheritance. Overloading. Getting called class name

I have good oop understanding but poor understanding of its implementation in php...
I have the following code, hope it's self documented =).
I need to have BB in the output
class A{
// I can't copy function::classname() to all my descendant classes
static function classname(){
echo __CLASS__;
}
}
class B extends A{
static function test(){
self::classname();
}
function test1(){
self::classname();
}
//i have A LOT of static and non-static functions using self::classname() in their code
// I can't copy all them to base class
}
$v = new B();
B::test();
$v->test1();
I'm stuck with static:: and self:: syntax
PS: another crazy question I've come across:
Suppose I have
function doSomething(){
echo $this->id;
}
Sometimes it gets into the static contexts. Yes, I know, that's because my bad application design. But is it possible to create a second(mirror, overloading) function
static function doSomething(){
echo false;
}
It means that using
$obj->doSomething() returns id and using Class::doSomething() returns false
Question 3:
Is it possible to get property default value in static context an property value in non-static context automatically?
Have a look at late static binding.
class A {
static function classname() {
echo __CLASS__;
}
static function test1() {
static::classname();
}
}
class B extends A {
static function classname() {
echo __CLASS__;
}
}
$v = new B();
B::test1();
$v->test1();
Or as pointed out by Long Ears in the comments, assuming php 5.3.0+ you can use get_called_class()
class A {
static function classname() {
echo get_called_class();
}
// this can be defined in either class A or B without affecting the output
static function test1() {
static::classname();
}
}
class B extends A {
}
$v = new B();
B::test1();
$v->test1();
Outputs:
BB
Regarding your second "crazy" question, see the Magic Methods. Basically, you would need to implement something like:
class Foo
{
public function __call($name, $arguments)
{
// call the _$name function
}
public static function __callStatic($name, $arguments)
{
// call the _{$name}_static function
}
private function _bar()
{
}
private static function _bar_static()
{
}
}
$foo = new Foo();
$foo->bar();
Foo::bar();
it's possible to add a static method like this
class Foo {
public static function __callStatic() {
// ....
}
}
// in Other file
// Call the static method
Foo-->__callStatic()
and call it on an other file (In php ) ?

static class inheritant not work in PHP?

abstract class base {
abstract public function test();
public function run()
{
self::test();
}
}
class son extends base {
public function test()
{
echo 1;
}
}
son::run();
It reports:
Fatal error: Cannot call abstract
method base::test()
But son::test() works,why and is there a way to fix?
"self" is lexically scoped, that is, if you use "self" in a method of Base, "self" means "Base", no matter how you call this method at run time. php5.3 introduced a new kind of dynamic binding, which, ironically enough, is called "static". The following works as expected in php 5.3
abstract class base {
abstract public static function test();
static public function run()
{
static::test();
}
}
class son extends base {
static public function test()
{
echo 1;
}
}
son::run();
Of course:
Fatal error: Cannot call abstract method base::test()
It has no method body you could call. If run() is supposed to be a Template Method, you refer to the class scope with $this instead of self and then create an instance of $son to call run() on it, e.g.
abstract class BaseClass {
abstract public function test();
public function run()
{
$this->test();
}
}
class Son extends BaseClass {
public function test()
{
echo 1;
}
}
$son = new Son;
$son->run(); // 1
which is rather odd, because then you could have just as well called test() directly.
Also note that in your example
son::run();
is wrong, because the run() method is not declared static and while PHP will execute run() nonetheless, it is considered wrong usage and will raise an E_STRICT error. However, if you were to define run() static, you could no longer reference $this, because a static method is not invoked from instance scope, but class scope.
Edit I was about to add the PHP5.3 solution, but see that #erenon already did that, while I was typing, so I only add the appropriate reference in the PHP Manual on Late Static Binding.
Abstract methods do not have an implementation, and thus cannot be called. If the method is not defined as abstract, and actually has an implementation, then it can be executed by your code. For example:
public function test(){
echo "Hello from base!";
}
Factory/singleton pattern mix:
class Base
{
static private $instance;
static function getSon() {
if (null === self::$instance) {
self::$instance = new Son;();
}
return self::$instance;
}
}
class Son
{
public function test() {
echo 1;
}
}
Base::getSon()->test(); //1

How do I get a PHP class constructor to call its parent's parent's constructor?

I need to have a class constructor in PHP call its parent's parent's (grandparent?) constructor without calling the parent constructor.
// main class that everything inherits
class Grandpa
{
public function __construct()
{
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
}
}
I know this is a bizarre thing to do and I'm attempting to find a means that doesn't smell bad but nonetheless, I'm curious if it's possible.
The ugly workaround would be to pass a boolean param to Papa indicating that you do not wish to parse the code contained in it's constructor. i.e:
// main class that everything inherits
class Grandpa
{
public function __construct()
{
}
}
class Papa extends Grandpa
{
public function __construct($bypass = false)
{
// only perform actions inside if not bypassing
if (!$bypass) {
}
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
$bypassPapa = true;
parent::__construct($bypassPapa);
}
}
You must use Grandpa::__construct(), there's no other shortcut for it. Also, this ruins the encapsulation of the Papa class - when reading or working on Papa, it should be safe to assume that the __construct() method will be called during construction, but the Kiddo class does not do this.
class Grandpa
{
public function __construct()
{}
}
class Papa extends Grandpa
{
public function __construct()
{
//call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
//this is not a bug, it works that way in php
Grandpa::__construct();
}
}
Beautiful solution using Reflection.
<?php
class Grandpa
{
public function __construct()
{
echo "Grandpa's constructor called\n";
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo "Papa's constructor called\n";
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
echo "Kiddo's constructor called\n";
$reflectionMethod = new ReflectionMethod(get_parent_class(get_parent_class($this)), '__construct');
$reflectionMethod->invoke($this);
}
}
$kiddo = new Kiddo();
$papa = new Papa();
I ended up coming up with an alternative solution that solved the problem.
I created an intermediate class that extended Grandpa.
Then both Papa and Kiddo extended that class.
Kiddo required some intermediate functionality of Papa but didn't like it's constructor so the class has that additional functionality and both extend it.
I've upvoted the other two answers that provided valid yet ugly solutions for an uglier question:)
Another option that doesn't use a flag and might work in your situation:
<?php
// main class that everything inherits
class Grandpa
{
public function __construct(){
$this->GrandpaSetup();
}
public function GrandpaSetup(){
$this->prop1 = 'foo';
$this->prop2 = 'bar';
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
$this->prop1 = 'foobar';
}
}
class Kiddo extends Papa
{
public function __construct()
{
$this->GrandpaSetup();
}
}
$kid = new Kiddo();
echo "{$kid->prop1}\n{$kid->prop2}\n";
I agree with "too much php", try this:
class Grandpa
{
public function __construct()
{
echo 'Grandpa<br/>';
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo 'Papa<br/>';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
echo 'Kiddo<br/>';
Grandpa::__construct();
}
}
$instance = new Kiddo;
I got the result as expected:
Kiddo
Grandpa
This is a feature not a bug, check this for your reference:
https://bugs.php.net/bug.php?id=42016
It is just the way it works. If it sees it is coming from the right context this call version does not enforce a static call.
Instead it will simply keep $this and be happy with it.
parent::method() works in the same way, you don't have to define the method as static but it can be called in the same context. Try this out for more interesting:
class Grandpa
{
public function __construct()
{
echo 'Grandpa<br/>';
Kiddo::hello();
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo 'Papa<br/>';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
echo 'Kiddo<br/>';
Grandpa::__construct();
}
public function hello()
{
echo 'Hello<br/>';
}
}
$instance = new Kiddo;
It also works as expected:
Kiddo
Grandpa
Hello
But if you try to initialize a new Papa, you will get an E_STRICT error:
$papa = new Papa;
Strict standards: Non-static method Kiddo::hello() should not be called statically, assuming $this from incompatible context
You can use instanceof to determine if you can call a Children::method() in a parent method:
if ($this instanceof Kiddo) Kiddo::hello();
There's an easier solution for this, but it requires that you know exactly how much inheritance your current class has gone through. Fortunately, get_parent_class()'s arguments allow your class array member to be the class name as a string as well as an instance itself.
Bear in mind that this also inherently relies on calling a class' __construct() method statically, though within the instanced scope of an inheriting object the difference in this particular case is negligible (ah, PHP).
Consider the following:
class Foo {
var $f = 'bad (Foo)';
function __construct() {
$this->f = 'Good!';
}
}
class Bar extends Foo {
var $f = 'bad (Bar)';
}
class FooBar extends Bar {
var $f = 'bad (FooBar)';
function __construct() {
# FooBar constructor logic here
call_user_func(array(get_parent_class(get_parent_class($this)), '__construct'));
}
}
$foo = new FooBar();
echo $foo->f; #=> 'Good!'
Again, this isn't a viable solution for a situation where you have no idea how much inheritance has taken place, due to the limitations of debug_backtrace(), but in controlled circumstances, it works as intended.
You can call Grandpa::__construct from where you want and the $this keyword will refer to your current class instance. But be carefull with this method you cannot access to protected properties and methods of current instance from this other context, only to public elements. => All work and officialy supported.
Example
// main class that everything inherits
class Grandpa
{
public function __construct()
{
echo $this->one; // will print 1
echo $this->two; // error cannot access protected property
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public $one = 1;
protected $two = 2;
public function __construct()
{
Grandpa::__construct();
}
}
new Kiddo();
Funny detail about php: extended classes can use non-static functions of a parent class in a static matter. Outside you will get a strict error.
error_reporting(E_ALL);
class GrandPa
{
public function __construct()
{
print("construct grandpa<br/>");
$this->grandPaFkt();
}
protected function grandPaFkt(){
print(">>do Grandpa<br/>");
}
}
class Pa extends GrandPa
{
public function __construct()
{ parent::__construct();
print("construct Pa <br/>");
}
public function paFkt(){
print(">>do Pa <br>");
}
}
class Child extends Pa
{
public function __construct()
{
GrandPa::__construct();
Pa::paFkt();//allright
//parent::__construct();//whatever you want
print("construct Child<br/>");
}
}
$test=new Child();
$test::paFkt();//strict error
So inside a extended class (Child) you can use
parent::paFkt();
or
Pa::paFkt();
to access a parent (or grandPa's) (not private) function.
Outside class def
$test::paFkt();
will trow strict error (non static function).
<?php
class grand_pa
{
public function __construct()
{
echo "Hey I am Grand Pa <br>";
}
}
class pa_pa extends grand_pa
{
// no need for construct here unless you want to do something specifically within this class as init stuff
// the construct for this class will be inherited from the parent.
}
class kiddo extends pa_pa
{
public function __construct()
{
parent::__construct();
echo "Hey I am a child <br>";
}
}
new kiddo();
?>
Of course this expects you do not need to do anything within the construct of the pa_pa. Running this will output :
Hey I am Grand Pa
Hey I am a child
Ok, Yet another ugly solution:
Create a function in Papa like:
protected function call2Granpa() {
return parent::__construct();
}
Then in Kiddo you use:
parent::call2Granpa(); //instead of calling constructor in Papa.
I think it could work... I haven't test it, so I'm not sure if the
objects are created correctly.
I used this approach but with non-constructor functions.
// main class that everything inherits
class Grandpa
{
public function __construct()
{
$this->___construct();
}
protected function ___construct()
{
// grandpa's logic
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
parent::___construct();
}
}
note that "___construct" is not some magic name, you can call it "doGrandpaStuff".
class Grandpa
{
public function __construct()
{
echo"Hello Kiddo";
}
}
class Papa extends Grandpa
{
public function __construct()
{
}
public function CallGranddad()
{
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
}
public function needSomethingFromGrandDad
{
parent::CallGranddad();
}
}
from php 7 u can use
parent::parent::__construct();

Categories