2012-07-04 27 views
42

Czy mogę zadeklarować metodę w obiekcie jako metodę statyczną i niestatyczną o tej samej nazwie, która wywołuje metodę statyczną?PHP - czy można zadeklarować metodę statyczną i niestatyczną?

Chcę utworzyć klasę, która ma statyczną metodę "wyślij" i niestatyczną metodę, która wywołuje funkcję statyczną. Na przykład:

class test { 
    private $text; 
    public static function instance() { 
     return new test(); 
    } 

    public function setText($text) { 
     $this->text = $text; 
     return $this; 
    } 

    public function send() { 
     self::send($this->text); 
    } 

    public static function send($text) { 
     // send something 
    } 
} 

Chcę, aby móc wywołać funkcję tych dwóch zostało

test::send("Hello World!"); 

i

test::instance()->setText("Hello World")->send(); 

jest to możliwe?

+4

Dlaczego chcesz to zrobić, jeśli mogę zapytać? – PeeHaa

+0

[może statycznych członków użyć niestatycznych członków i na odwrót?] (Http://stackoverflow.com/questions/2204128/could-static-members-use-nonstatic-members-and-vice-versa) –

+0

Odpowiedź brzmi nie btw , ale jestem naprawdę ciekawy, dlaczego myślisz, że chcesz to zrobić. – PeeHaa

Odpowiedz

55

Możesz może zrobić, ale to trochę trudne. Musisz to zrobić z przeciążeniem: the __call and __callStatic magicznych metod.

class test { 
    private $text; 
    public static function instance() { 
     return new test(); 
    } 

    public function setText($text) { 
     $this->text = $text; 
     return $this; 
    } 

    public function sendObject() { 
     self::send($this->text); 
    } 

    public static function sendText($text) { 
     // send something 
    } 

    public function __call($name, $arguments) { 
     if ($name === 'send') { 
      call_user_func(array($this, 'sendObject')); 
     } 
    } 

    public function __callStatic($name, $arguments) { 
     if ($name === 'send') { 
      call_user_func(array('test', 'sendText'), $arguments[0]); 
     } 
    } 
} 

To nie jest idealnym rozwiązaniem, ponieważ to sprawia, że ​​Twój kod trudniejsze do wykonania, ale to będzie działać, o ile masz PHP> = 5,3.

+24

To sprawia, że ​​moje oczy b̢̗̫͕l͓̫͈e҉͍̖͙ḙ̣̭̦̫̞͟d̼. Nie odrzucę go, ponieważ ostrzegłeś go, że ten rodzaj kodowania nie zmniejszy jego życia i jest pomocny. Ale nadal: < –

+10

@lonesomeday Do głosowania tylko dlatego, że masz cierpliwość, aby napisać kod, który praktycznie nie ma namacalnego zastosowania! ale odpowiada na pytanie :-) –

+3

@Truth Tak. Powinno być "możesz to zrobić, ale ty naprawdę nie powinieneś". – lonesomeday

3

Nie można nie mieć dwóch metod o tej samej nazwie. Możesz zrobić to samo, zmieniając nazwę jednej z metod. Zmiana nazwy test::send("Hello World!"); na test::sendMessage("Hello World!"); zadziała. Po prostu utworzyłbym metodę pojedynczego wysyłania z opcjonalnym argumentem tekstowym, który zmienia sposób działania tej metody.

public function send($text = false) { 
    if (!$text) { 
     $text = $this -> text; 
    } 

    // Send something 
} 

Podsumowując, dlaczego w ogóle potrzebujesz funkcji statycznej.

+3

Zmiana nazwy metody statycznej jest zdecydowanie rozsądnym sposobem na zrobienie tego. – lonesomeday

-1

Przepraszamy za uderzenie starego wątku, ale chciałbym rozwinąć odpowiedź @lonesomeday. (Dzięki @lonesomeday za początkową próbkę kodu.)

Eksperymentowałem również z tym, ale nie chciałem wywoływać metod, jak je nazywał w oryginalnym poście. Zamiast tego mam następujące dane, które wydaje pracować:

class Emailer { 

    private $recipient; 

    public function to($recipient) 
    { 
     $this->recipient = $recipient; 
     return $this; 
    } 

    public function sendNonStatic() 
    { 
     self::mailer($this->recipient); 
    } 

    public static function sendStatic($recipient) 
    { 
     self::mailer($recipient); 
    } 

    public function __call($name, $arguments) 
    { 
     if ($name === 'send') { 
      call_user_func(array($this, 'sendNonStatic')); 
     } 
    } 

    public static function mailer($recipient) 
    { 
     // send() 
     echo $recipient . '<br>'; 
    } 

    public static function __callStatic($name, $arguments) 
    { 
     if ($name === 'send') { 
      call_user_func(array('Emailer', 'sendStatic'), $arguments[0]); 
     } 
    } 
} 

Emailer::send('[email protected]'); 

$Emailer = new Emailer; 
$Emailer->to('[email protected]'); 
$Emailer->send(); 
-1

Zgadzam się, że należy unikać za wszelką cenę, ale są pewne przypadki, w których może to być przydatne.

W większości przypadków spowoduje to, że twój kod stanie się nieczytelny i nie będzie można nim zarządzać.

Uwierz mi, byłem na tej ścieżce.

Oto przykład scenariusza użycia, w którym może być nadal praktyczny.

Rozszerzam klasę pliku CakePHP 3.0 jako moją domyślną klasę obsługi plików.

Chciałem umieścić nieruchomy typ mime.

W niektórych przypadkach mam nazwę pliku zamiast rzeczywistego pliku, a niektóre założenia muszą być wykonane w tym przypadku.(jeśli plik istnieje, spróbuj uzyskać mim od niego, użyj rozszerzonej nazwy pliku)

Innym razem, gdy faktycznie zainicjowałem obiekt, domyślna metoda mime() powinna działać, ale jeśli się nie powiedzie, nazwa pliku musi zostać wyodrębniona z obiektu, a zamiast tego powinna zostać wywołana metoda statyczna.

Aby uniknąć nieporozumień moim celem było uzyskać typ MIME przez wywołanie tej samej metody:

Static:

NS\File::type('path/to/file.txt') 

jako przedmiot

$f = new NS\File('path/to/file.txt'); 
$f->type(); 

Oto mój przykład rozszerzona klasa:

<?php 

namespace NS; 

class File extends \Cake\Utility\File 
{ 

    public function __call($method, $args) { 
     return call_user_func_array([get_called_class(), 'obj'.ucfirst($method)], $args); 
    } 
    public static function __callStatic($method, $args) { 
     return call_user_func_array([get_called_class(), 'static'.ucfirst($method)], $args); 
    } 

    public function objType($filename=null){ 
     $mime = false; 
     if(!$filename){ 
      $mime = $this->mime(); 
      $filename = $this->path; 
     } 
     if(!$mime){ 
      $mime = static::getMime($filename); 
     } 
     return $mime; 
    } 

    public static function staticType($filename=null){ 
     return static::getMime($filename); 
    } 

    public static function getMime($filename = null) 
    { 
     $mimes = [ 
      'txt' => 'text/plain', 
      'htm' => 'text/html', 
      'html' => 'text/html', 
      'php' => 'text/html', 
      'ctp' => 'text/html', 
      'twig' => 'text/html', 
      'css' => 'text/css', 
      'js' => 'application/javascript', 
      'json' => 'application/json', 
      'xml' => 'application/xml', 
      'swf' => 'application/x-shockwave-flash', 
      'flv' => 'video/x-flv', 
      // images 
      'png' => 'image/png', 
      'jpe' => 'image/jpeg', 
      'jpeg' => 'image/jpeg', 
      'jpg' => 'image/jpeg', 
      'gif' => 'image/gif', 
      'bmp' => 'image/bmp', 
      'ico' => 'image/vnd.microsoft.icon', 
      'tiff' => 'image/tiff', 
      'tif' => 'image/tiff', 
      'svg' => 'image/svg+xml', 
      'svgz' => 'image/svg+xml', 
      // archives 
      'zip' => 'application/zip', 
      'rar' => 'application/x-rar-compressed', 
      'exe' => 'application/x-msdownload', 
      'msi' => 'application/x-msdownload', 
      'cab' => 'application/vnd.ms-cab-compressed', 
      // audio/video 
      'mp3' => 'audio/mpeg', 
      'qt' => 'video/quicktime', 
      'mov' => 'video/quicktime', 
      // adobe 
      'pdf' => 'application/pdf', 
      'psd' => 'image/vnd.adobe.photoshop', 
      'ai' => 'application/postscript', 
      'eps' => 'application/postscript', 
      'ps' => 'application/postscript', 
      // ms office 
      'doc' => 'application/msword', 
      'rtf' => 'application/rtf', 
      'xls' => 'application/vnd.ms-excel', 
      'ppt' => 'application/vnd.ms-powerpoint', 
      // open office 
      'odt' => 'application/vnd.oasis.opendocument.text', 
      'ods' => 'application/vnd.oasis.opendocument.spreadsheet', 
     ]; 
     $e = explode('.', $filename); 
     $ext = strtolower(array_pop($e)); 
     if (array_key_exists($ext, $mimes)) { 
      $mime = $mimes[$ext]; 
     } elseif (function_exists('finfo_open') && is_file($filename)) { 
      $finfo = finfo_open(FILEINFO_MIME); 
      $mime = finfo_file($finfo, $filename); 
      finfo_close($finfo); 
     } else { 
      $mime = 'application/octet-stream'; 
     } 
     return $mime; 
    } 
} 
0

chciałbym zrobić ukrytą klasy jako konstruktora i powrócić które ukryte klasy wewnątrz klasy nadrzędnej, która ma metody statyczne równe ukrytych metod Klasa:

// Parent class 

class Hook { 

    protected static $hooks = []; 

    public function __construct() { 
     return new __Hook(); 
    } 

    public static function on($event, $fn) { 
     self::$hooks[$event][] = $fn; 
    } 

} 


// Hidden class 

class __Hook { 

    protected $hooks = []; 

    public function on($event, $fn) { 
     $this->hooks[$event][] = $fn; 
    } 

} 

nazwać statycznie:

Hook::on("click", function() {}); 

nazwać to dynamicznie:

0

Jest o wiele prostszy sposób.

class MyClass { 

    private $r = "I'm regular!"; 

    private static $s = "I'm static!"; 

    public function method() { 
     if (isset($this) && $this instanceof self) { 
      // Regular call 
      echo $this->r; 
     } else { 
      // Static call 
      echo static::$s; 
     } 
    } 

} 

Teraz można łatwo zrobić:

(new MyClass())->method(); 
// I'm regular! 

lub

MyClass::method(); 
// I'm static! 

Można użyć tej ramy, aby osiągnąć wszystko, czego opisać w pytaniu.

Powiązane problemy