[php] Override function i.c.m. keyword self probleem.

Pagina: 1
Acties:
  • 279 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
In navolging van de reactie van creepy op: [PHP] Class casten onmogelijk? hierbij mijn probleem.

Ik wil graag een function overriden van een classe. In deze functie wordt gebruik gemaakt van het keyword self, waarmee er nieuwe instanties van zichzelf worden aangemaakt. Op het moment dat ik de klasse extend maakt hij instanties aan van de orginele classe ipv de classe die extend. Een stukje code om dit toe te lichten:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class A
{
  public $a;

  function __construct($iDepth)
  {
    if ($iDepth==1)
    {
      $this->a = new self(0);
    }
  }
}

class B extends A
{
  function __construct($iDepth)
  {
    parent::__construct($iDepth);
  }
}

$o = new B(1);
var_dump($o->a);

//output:
// object(A)#2 (1) { ["a"]=> NULL } 


Ik zou een instantie van classe B verwachten. Om dit probleem op een andere manier op te lossen heb ik geprobeerd $o->a te casten naar B

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class A
{
  public $a;

  function __construct($iDepth)
  {
    if ($iDepth==1)
    {
      $this->a = new self(0);
    }
  }
}

class B extends A
{
  function __construct($iDepth)
  {
    parent::__construct($iDepth);
  }
}

$o = new B(1);
$o->a = (B)$o->a;


Dit geeft echter een parse error.

Het probleem is op te lossen door keyword self te vervangen door $this, waardoor de binding later gebeurt, ware het niet dat classe A een classe is van Zend Framework en het dus beter is om dit niet aan te passen.

Wie weet er een goede workaround?


P.S. Heeft dit trouwens te maken met Late Static Binding (zie: http://blog.felho.hu/what...-late-static-binding.html)? Dit wordt opgelost in versie 5.3 van php.

Acties:
  • 0 Henk 'm!

Verwijderd

Als je wilt zorgen dat je niks in het Zend Framework hoeft aan te passen kun je natuurlijk ook gewoon de constructor van klasse B zo maken dat hij het public field zelf nog eens aanpast.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A {
    public $a;

    function __construct($iDepth) {
        if ($iDepth == 1) {
            $this->a = new self(0);
        }
    }
}

class B extends A {
    function __construct($iDepth) {
        parent::__construct($iDepth);
        if ($iDepth == 1) {
            $this->a = new self(0);
        }
    }
}


Dit is natuurlijk niet helemaal netjes en ik begrijp ook niet precies waar je het voor nodig zou hebben, maar het werkt wel natuurlijk ;)

Edit: Ik heb net even snel dat verhaal over Late static binding gelezen en het lijkt hier inderdaad wel op. Het enige verschil is dat je volgens mij een constructor niet kunt zien als een static method en het Late static binding verhaal dus niet van toepassing is op jouw probleem.

[ Voor 19% gewijzigd door Verwijderd op 14-01-2008 17:30 ]


Acties:
  • 0 Henk 'm!

  • FragFrog
  • Registratie: September 2001
  • Laatst online: 22:47
Verwijderd schreef op maandag 14 januari 2008 @ 17:05:
Ik zou een instantie van classe B verwachten.
En die krijg je ook:
PHP:
1
echo get_class($o); // outputs: B;


Wat is het probleem als $a door A gedefinieerd wordt uberhaupt? :? Ja, self zal een object van zichzelf geven, daar valt weinig aan te doen, maar waarom wil je dat? :)

[ Voor 14% gewijzigd door FragFrog op 14-01-2008 17:31 ]

[ Site ] [ twitch ] [ jijbuis ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
@everyone
Zie hier nog een discussie op bugs.php.net: http://bugs.php.net/bug.php?id=30934

@Stierenoog

Inderdaad, maar het lijkt er zoveel op, misschien triggert dit iets bij iemand, dat het bijvoorbeeld met late binding te maken heeft.

@FrapFrog:

$o is een instantie van B, maar $o->a niet.

uit Zend_Mail_Part:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected function _cacheContent()
    {
        // caching content if we can't fetch parts
        if ($this->_content === null && $this->_mail) {
            $this->_content = $this->_mail->getRawContent($this->_messageNum);
        }

        if (!$this->isMultipart()) {
            return;
        }

        // split content in parts
        $boundary = $this->getHeaderField('content-type', 'boundary');
        if (!$boundary) {
            throw new Zend_Mail_Exception('no boundary found in content type to split message');
        }
        $parts = Zend_Mime_Decode::splitMessageStruct($this->_content, $boundary);
        $counter = 1;
        foreach ($parts as $part) {
            $this->_parts[$counter++] = new self(array('headers' => $part['header'], 'content' => $part['body']));
        }
    }


Wanneer er in een e-mail een boundary is gebruikt, wordt hierop gesplits en een nieuwe parts aangemaakt. Ik wil echter graag een verwijzing naar de parent hebben, zodat ik als ik een text/html part heb kan controleren of deze in een multipart/relative valt om de embedded images te kunnen parsen. Echter dit is niet aanwezig, en om zelf de complete tree opbouw te herschrijven dacht ik zo een nette oplossing te creeëren.

Wat ik eigelijk wil is:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//attribuut, parent toegevoegd
private $_parent;

//hier $parent toegevoegd
 public function __construct(array $params, $parent)
    {
$this->_parent = $parent;
      .......
    }

protected function _cacheContent()
    {
        // caching content if we can't fetch parts
        if ($this->_content === null && $this->_mail) {
            $this->_content = $this->_mail->getRawContent($this->_messageNum);
        }

        if (!$this->isMultipart()) {
            return;
        }

        // split content in parts
        $boundary = $this->getHeaderField('content-type', 'boundary');
        if (!$boundary) {
            throw new Zend_Mail_Exception('no boundary found in content type to split message');
        }
        $parts = Zend_Mime_Decode::splitMessageStruct($this->_content, $boundary);
        $counter = 1;
        foreach ($parts as $part) {
//hier dus $this toegevoegd om parent mee te geven
            $this->_parts[$counter++] = new self(array('headers' => $part['header'], 'content' => $part['body']), $this);
        }
    }

[ Voor 71% gewijzigd door Verwijderd op 14-01-2008 17:55 ]


Acties:
  • 0 Henk 'm!

  • FragFrog
  • Registratie: September 2001
  • Laatst online: 22:47
Kun je dan niet simpelweg dit doen?
PHP:
1
echo $o -> a -> isMultipart(); // true || false?


Ken de precieze details niet van de class, maar dat lijkt ook je die informatie te geven? :)

//edit
Ow wacht, dat wil je dus juist van de parent weten 8)7 Heb je daar verder geen verwijzing naar? Zou toch ook beschikbaar moeten zijn als je'm aanmaakt?

[ Voor 35% gewijzigd door FragFrog op 14-01-2008 18:37 ]

[ Site ] [ twitch ] [ jijbuis ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
FragFrog schreef op maandag 14 januari 2008 @ 18:34:
Kun je dan niet simpelweg dit doen?
PHP:
1
echo $o -> a -> isMultipart(); // true || false?


Ken de precieze details niet van de class, maar dat lijkt ook je die informatie te geven? :)

//edit
Ow wacht, dat wil je dus juist van de parent weten 8)7 Heb je daar verder geen verwijzing naar? Zou toch ook beschikbaar moeten zijn als je'm aanmaakt?
Inderdaad, maar dit is de gewenste situatie, waarin ik de orginele code heb bewerkt. Dat wil ik echter niet, omdat dit 1 op 1 de code van Zend Framework moet blijven. Heb het nu opgelost door zelf container classes aan te maken.
Pagina: 1