php - Come sovrascrivere la funzione tratti e chiamarla dalla funzione ignorata?


Scenario:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A;

    function calc($v) {
        $v++;
        return A::calc($v);
    }
}

print (new MyClass())->calc(2); // should print 4

Questo codice non funziona e non riesco a trovare un modo per chiamare una funzione tratto come se fosse ereditata. Ho provato a chiamare self::calc($v) , static::calc($v) , parent::calc($v) , A::calc($v) e il seguente:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A {
        calc as traitcalc;
    }

    function calc($v) {
        $v++;
        return traitcalc($v);
    }
}

Niente funziona.

C'è un modo per farlo funzionare o devo scavalcare completamente la funzione di tratto che è molto più complessa di questa :)




Answers


Il tuo ultimo era quasi arrivato:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A {
        calc as protected traitcalc;
    }

    function calc($v) {
        $v++;
        return $this->traitcalc($v);
    }
}

Il tratto non è una classe. Non è possibile accedere ai suoi membri direttamente. È fondamentalmente solo copia e incolla automatizzata ...




Se la classe implementa direttamente il metodo, non utilizzerà la versione dei tratti. Forse quello a cui stai pensando è:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    function calc($v) {
        return $v+2;
    }
}

class MyChildClass extends MyClass{
}

class MyTraitChildClass extends MyClass{
    use A;
}

print (new MyChildClass())->calc(2); // will print 4

print (new MyTraitChildClass())->calc(2); // will print 3

Poiché le classi figlie non implementano direttamente il metodo, per prima cosa useranno quella del tratto se altrimenti usano quella della classe genitore.

Se vuoi, il tratto può usare il metodo nella classe genitore (presumendo che tu sappia che il metodo sarebbe lì), ad es

trait A {
    function calc($v) {
        return parent::calc($v*3);
    }
}
// .... other code from above
print (new MyTraitChildClass())->calc(2); // will print 8 (2*3 + 2)

Puoi anche fornire dei modi per eseguire l'override, ma puoi comunque accedere al metodo tratto come segue:

trait A {
    function trait_calc($v) {
        return $v*3;
    }
}

class MyClass {
    function calc($v) {
        return $v+2;
    }
}


class MyTraitChildClass extends MyClass{
    use A {
      A::trait_calc as calc;
    }
}


class MySecondTraitChildClass extends MyClass{
    use A {
      A::trait_calc as calc;
    }

    public function calc($v) {
      return $this->trait_calc($v)+.5;
    }
}


print (new MyTraitChildClass())->calc(2); // will print 6
echo "\n";
print (new MySecondTraitChildClass())->calc(2); // will print 6.5

Puoi vederlo funzionare su http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5




Un approccio alternativo se interessato - con una classe intermedia extra per usare il normale modo OOO. Questo semplifica l'utilizzo con parent :: methodname

trait A {
    function calc($v) {
        return $v+1;
    }
}

// an intermediate class that just uses the trait
class IntClass {
    use A;
}

// an extended class from IntClass
class MyClass extends IntClass {
    function calc($v) {
        $v++;
        return parent::calc($v);
    }
}



Usando un'altra caratteristica:

trait ATrait {
    function calc($v) {
        return $v+1;
    }
}

class A {
    use ATrait;
}

trait BTrait {
    function calc($v) {
        $v++;
        return parent::calc($v);
    }
}

class B extends A {
    use BTrait;
}

print (new B())->calc(2); // should print 4