Sınıf Yöntemler veya Class yeniden tanımlayın

9 Cevap php

Tipik devralma kullanmadan bir sınıf veya yöntemlerden bazıları yeniden tanımlamak için herhangi bir yolu var mı? Örneğin:

class third_party_library {
    function buggy_function() {
        return 'bad result';
    }
    function other_functions(){
        return 'blah';
    }
}

Ben değiştirmek için ne yapabilirim buggy_function()? Açıkçası bu benim yapmak istiyorum ne

class third_party_library redefines third_party_library{
    function buggy_function() {
        return 'good result';
    }
    function other_functions(){
        return 'blah';
    }
}

Bu benim kesin ikilem şudur: Ben kodumu tatili bir üçüncü taraf kitaplığı güncellendi. Gelecek güncellemelerin kodu kırmak gibi ben doğrudan kütüphane değiştirmek istemiyorum. Ben sınıf yöntemi yerine kusursuz bir şekilde arıyorum.

Ben bunu yapabilirim diyor bu library bulduk, ama 4 yaşında gibi dikkatli yaşıyorum.

EDIT:

Ben magical_third_party_library ya da çünkü çerçeve sınırlamaları başka bir şey için third_party_library adlı sınıfını adlandırmak olamayacağını açıklık olmalıdır.

Benim amaçlar için, sadece sınıf bir işlev eklemek mümkün olurdu? Ben bir denilen bir şey C # ile bunu düşünüyorum "kısmi sınıf."

9 Cevap

Bu deniyor monkey patching. Ama, PHP bunun için doğal destek yok.

Diğerleri de belirttiği gibi olsa da, runkit library diline destek eklemek için mevcuttur ve classkit için devamıdır. Onun yaratıcısı tarafından abandoned olmuştur görünüyordu olsa da, (daha sonra PHP 5.2 ile uyumlu olup olduğunu belirtti sahip), proje artık bir new home and maintainer sahip görünmektedir.

Hala can't say I'm a fan anlay. Kod dizeleri değerlendirerek değişiklik yapma her zaman potansiyel olarak tehlikeli ve hata ayıklamak zor bana görünüyordu.

Yine de, runkit_method_redefine appears to be what you're looking for, and an example of its use can be found in /tests/runkit_method_redefine.phpt depo:

runkit_method_redefine('third_party_library', 'buggy_function', '',
    'return \'good result\''
);

runkit iyi bir çözüm gibi görünüyor ama onun varsayılan ve bölümleri tarafından etkin değil hala deneyseldir. Yani birlikte bir sınıf dosyası işlev tanımları yerini küçük bir sınıf hacklendi. Örnek kullanım:

class Patch {

private $_code;

public function __construct($include_file = null) {
    if ( $include_file ) {
        $this->includeCode($include_file);
    }
}

public function setCode($code) {
    $this->_code = $code;
}

public function includeCode($path) {

    $fp = fopen($path,'r');
    $contents = fread($fp, filesize($path));
    $contents = str_replace('<?php','',$contents);
    $contents = str_replace('?>','',$contents);
    fclose($fp);        

    $this->setCode($contents);
}

function redefineFunction($new_function) {

    preg_match('/function (.+)\(/', $new_function, $aryMatches);
    $func_name = trim($aryMatches[1]);

    if ( preg_match('/((private|protected|public) function '.$func_name.'[\w\W\n]+?)(private|protected|public)/s', $this->_code, $aryMatches) ) {

        $search_code = $aryMatches[1];

        $new_code = str_replace($search_code, $new_function."\n\n", $this->_code);

        $this->setCode($new_code);

        return true;

    } else {

        return false;

    }

}

function getCode() {
    return $this->_code;
}
}

Daha sonra modifiye edilmiş ve yöntemleri yeniden tanımlamak üzere sınıfı içerir:

$objPatch = new Patch('path_to_class_file.php');
$objPatch->redefineFunction("
    protected function foo(\$arg1, \$arg2)
    {   
        return \$arg1+\$arg2;
    }");

Ardından yeni kodu eval:

eval($objPatch->getCode());

Biraz kaba ama işe yarıyor!

Bütünlüğü uğruna - maymun yama runkit ile PHP mevcuttur. Ayrıntılar için, bkz: runkit_method_redefine().

Evet, deniyor extend:

<?php
class sd_third_party_library extends third_party_library
{
    function buggy_function() {
        return 'good result';
    }
    function other_functions(){
        return 'blah';
    }
}

Ben "sd" ile başlamaktadır. ;-)

Eğer yöntemleri geçersiz kılmak için bir sınıf genişletmek zaman, yöntemin imza orijinal maç olduğunu aklınızda bulundurun. Orijinal söyledi eğer Yani, örneğin buggy_function($foo, $bar), onu uzanan sınıfında parametreleri maç var.

PHP bu konuda oldukça ayrıntılı olduğunu.

Nasıl başka bir sınıfta sararak yaklaşık gibi

class Wrapper {
 private $third_party_library;
 function __construct() { $this->third_party_library = new Third_party_library(); }
 function __call($method, $args) {
  return call_user_func_array(array($this->third_party_library, $method), $args);
 }
}

Zend Studio ve PDT (temelli ide eclipse) araçları refractoring bazı inşa etmişlerdir. Ama bunu yapmak için yöntemler inşa vardır.

Ayrıca tüm sistem kötü kod olmasını istemem. Yanlışlıkla üzerine denilebilir beri.

ok... hmm... don't tell my boss, but I will share the Aspect.class.php with you. It's something that (uppon calling hijackAspect($path);) "includes" your class with a nice proxy override on it.

http://agenciavalemais.com.br/roger/Aspect.class.php.zip

Eğer sadece orada sihirli _call dışında yöntemini yazma tarafından ihtiyaç arabası yöntemini geçersiz kılmak için Aspect sınıf uyarlayabilirsiniz.

ama sadece bir uyarı, tüm Require_once en kaldırmak veya dosya dahil listesinde ise sınıf özendirdiği yerine kontrol etmek için bir "ithalat" fonksiyonunu kullanmak zorunda olacak.

Alway orada yeni, doğru, yöntemi ile sınıfını genişleten ve bu sınıfı çağrı yerine adamcağız biri oluyor.

class my_better_class Extends some_buggy_class {
    function non_buggy_function() {
        return 'good result';
    }
}

(Berbat biçimlendirme için özür dilerim)

Sen runkit ile bunu yapmak mümkün olabilir. http://php.net/runkit