# BC break in 5.3.2 -> 5.3.3 with "parent::" and __call/__callStatic

- Thread: https://externals.io/message/49963
- Original archive: https://news-web.php.net/php.internals/49963
- Started by Giovanni Giacobbi on 2010-10-24T22:38:25+00:00
- Messages: 9
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #49963 — Giovanni Giacobbi — 2010-10-24T22:38:25+00:00

URL: https://externals.io/message/49963#49963

Greetings,

in reference to bug #52713 i'd like to inquire you about this decision which actually broke my codebase in different parts.

The situation is this one:

class ActiveRecord {

  public function __call($method, $args) {
    if ($method == "getFoo") {
      // implement some default behaviour for getFoo()
    }
  }

  public function __callStatic($method, $args) {
    // do some other stuff
  }
}


class Bar {
  // override getFoo() to add some specific behaviour
  public function getFoo() {
    // do the specific stuff
    parent::getFoo();
  }
}


Until version 5.3.2 this worked fine, starting from version 5.3.3 parent::getFoo() calls __callStatic() instead of __call().

This is a really bad BC change which i thought you decided to accept only in minor versions change and not patch-level versions change.

Anyway, I would even be willing to do some changes to my codebase, but what is the solution? I can't see any other way to do this with the obvious assumptions that my design is good and that I don't know anything about the parent class except there is a getFoo() method implemented somehow.

My wish is that you restore the 5.3.2 behaviour, which sounds very reasonable, and maybe introduce another way when you actually want to get rid of the context, something like static::

-- 
Giovanni Giacobbi

---

## #49964 — Stas Malyshev — 2010-10-24T22:41:44+00:00

URL: https://externals.io/message/49963#49964 · In reply to: #49963

Hi!

> class Bar {
>    // override getFoo() to add some specific behaviour
>    public function getFoo() {
>      // do the specific stuff
>      parent::getFoo();
>    }
> }

I think you meant Bar to extend ActiveRecord? But anyway, I think that 
this particular call should be done through __call, not __callStatic, 
since it's basically non-static call. The line between the two wasn't 
really well-defined in PHP (you could call static methods non-statically 
and vice versa) which is a pity but I think distinction can be made in 
this case.

-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #49965 — Etienne Kneuss — 2010-10-24T22:56:28+00:00

URL: https://externals.io/message/49963#49965 · In reply to: #49964

> Hi!
> 
> > […]
> 
> I think you meant Bar to extend ActiveRecord? But anyway, I think
> that this particular call should be done through __call, not
> __callStatic, since it's basically non-static call. The line between
> the two wasn't really well-defined in PHP (you could call static
> methods non-statically and vice versa) which is a pity but I think
> distinction can be made in this case.

Exactly, if Bar::getFoo is not called statically, parent::getFoo() will
not be a static call, it should not get through __callStatic.

Best,

> 
> -- 
> Stanislav Malyshev, Software Architect
> SugarCRM: http://www.sugarcrm.com/
> (408)454-6900 ext. 227
> 
> -- 
> 
> 
> 

-- 
Etienne Kneuss
http://www.colder.ch

---

## #49966 — Etienne Kneuss — 2010-10-24T23:04:00+00:00

URL: https://externals.io/message/49963#49966 · In reply to: #49965

> 
> > […]
> 
> Exactly, if Bar::getFoo is not called statically, parent::getFoo() will
> not be a static call, it should not get through __callStatic.
> 
> Best,

Oh, and #51176 seems bogus to me. "::" is not sufficient to indicate a
static call, neither is "self::", "static::", or "Foo::".

A call is only static if one of the two following conditions match:
    1) the target method is declared as static
    2) the call comes from an object-less scope

> 
> > […]
> 
> -- 
> Etienne Kneuss
> http://www.colder.ch
> 
> -- 
> 
> 
> 

-- 
Etienne Kneuss
http://www.colder.ch

---

## #49967 — Giovanni Giacobbi — 2010-10-24T23:23:02+00:00

URL: https://externals.io/message/49963#49967 · In reply to: #49966

> 
> > […]
> 
> Oh, and #51176 seems bogus to me. "::" is not sufficient to indicate a
> static call, neither is "self::", "static::", or "Foo::".
> 
> A call is only static if one of the two following conditions match:
>     1) the target method is declared as static
>     2) the call comes from an object-less scope
> 

I think you perfectly got the point. However, being actually non-defined, we need to choose between __call() and __callStatic(), and i think that number 2 is the only applicable criteria.

Note that for my problem, reverting commit 295706 in branch PHP_5_3 is enough to fix my problem, but it would break again 51176.

As this is a BC break compared to the 5.3.x series, IMHO it's the right way to go and then find another solution for 51176.

-- 
Giovanni Giacobbi

---

## #49973 — Daniel Convissor — 2010-10-26T14:48:22+00:00

URL: https://externals.io/message/49963#49973 · In reply to: #49965

> Exactly, if Bar::getFoo is not called statically, parent::getFoo() will
> not be a static call, it should not get through __callStatic.

That logic sounds good.  Unfortunately, things aren't behaving that way:

<?php

// Rework of code from http://bugs.php.net/bug.php?id=51176
class p {
        public function __call($n, $a) {
                echo "call\n";
        }

        public static function __callStatic($n, $a) {
                echo "callStatic\n";
        }
}

class c extends p {
        public function existing() {
                parent::non_existing();
        }
}

$c = new c;
echo 'static = ';
c::s();
echo 'object = ';
$c->o();
echo 'parent = ';
$c->existing();

echo `phpversion()` . "\n";


Thanks,

--Dan

-- 
 T H E   A N A L Y S I S   A N D   S O L U T I O N S   C O M P A N Y
            data intensive web and database programming
                http://www.AnalysisAndSolutions.com/
 4015 7th Ave #4, Brooklyn NY 11232  v: 718-854-0335 f: 718-854-0409

---

## #49974 — Richard Quadling — 2010-10-26T15:46:23+00:00

URL: https://externals.io/message/49963#49974 · In reply to: #49973

On 26 October 2010 15:48, Daniel Convissor
<danielc@analysisandsolutions.com> wrote:
> 
>
> > […]
>
> That logic sounds good.  Unfortunately, things aren't behaving that way:
>
> <?php
>
> // Rework of code from http://bugs.php.net/bug.php?id=51176
> class p {
>        public function __call($n, $a) {
>                echo "call\n";
>        }
>
>        public static function __callStatic($n, $a) {
>                echo "callStatic\n";
>        }
> }
>
> class c extends p {
>        public function existing() {
>                parent::non_existing();
>        }
> }
>
> $c = new c;
> echo 'static = ';
> c::s();
> echo 'object = ';
> $c->o();
> echo 'parent = ';
> $c->existing();
>
> echo `phpversion()` . "\n";
>
>
> Thanks,
>
> --Dan

So the calling context/scope is going to have to be used to determine
if the call should get to __call or __callStatic.

Is that possible? Appropriate? Easy to do? Done by Friday?


-- 
Richard Quadling
Twitter : EE : Zend
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY

---

## #50089 — Felipe Pena — 2010-11-03T01:38:43+00:00

URL: https://externals.io/message/49963#50089 · In reply to: #49963

2010/10/24 Giovanni Giacobbi <giovanni@giacobbi.net>

>
> Greetings,
>
> in reference to bug #52713 i'd like to inquire you about this decision
> which actually broke my codebase in different parts.
>
> The situation is this one:
>
> class ActiveRecord {
>
>  public function __call($method, $args) {
>    if ($method == "getFoo") {
>      // implement some default behaviour for getFoo()
>    }
>  }
>
>  public function __callStatic($method, $args) {
>    // do some other stuff
>  }
> }
>
>
> class Bar {
>  // override getFoo() to add some specific behaviour
>  public function getFoo() {
>    // do the specific stuff
>    parent::getFoo();
>  }
> }
>
>
> Until version 5.3.2 this worked fine, starting from version 5.3.3
> parent::getFoo() calls __callStatic() instead of __call().
>
> This is a really bad BC change which i thought you decided to accept only
> in minor versions change and not patch-level versions change.
>
> Anyway, I would even be willing to do some changes to my codebase, but what
> is the solution? I can't see any other way to do this with the obvious
> assumptions that my design is good and that I don't know anything about the
> parent class except there is a getFoo() method implemented somehow.
>
> My wish is that you restore the 5.3.2 behaviour, which sounds very
> reasonable, and maybe introduce another way when you actually want to get
> rid of the context, something like static::
>
>
The change has been reverted in SVN.


Thanks.

-- 
Regards,
Felipe Pena

---

## #50090 — jvlad — 2010-11-03T10:29:10+00:00

URL: https://externals.io/message/49963#50090 · In reply to: #50089

> > […]
> The change has been reverted in SVN.
>

Great. Is there any chance to see 5.3.4 anytime soon?

-j
