2012-07-04 27 views
42

Tôi có thể khai báo một phương thức trong một đối tượng dưới dạng phương thức tĩnh và không có cùng tên gọi phương thức tĩnh không?PHP - có thể khai báo phương thức tĩnh và không tĩnh

Tôi muốn tạo một lớp có phương thức tĩnh là "send" và phương thức nonstatic gọi hàm tĩnh. Ví dụ:

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 
    } 
} 

Tôi muốn để có thể gọi hàm trên hai được

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

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

là nó có thể?

+4

Tại sao bạn muốn làm điều đó nếu tôi có thể yêu cầu? – PeeHaa

+0

[thành viên tĩnh có thể sử dụng thành viên không phải là thành viên không và ngược lại?] (Http://stackoverflow.com/questions/2204128/could-static-members-use-nonstatic-members-and-vice-versa) –

+0

Câu trả lời là không có btw , nhưng tôi thực sự tò mò là tại sao bạn nghĩ bạn muốn làm điều đó. – PeeHaa

Trả lời

55

Bạn có thể làm điều này, nhưng hơi phức tạp một chút. Bạn phải làm điều đó với quá tải: the __call and __callStatic phương pháp ma thuật.

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]); 
     } 
    } 
} 

Đây không phải là giải pháp lý tưởng vì nó làm cho mã của bạn khó theo dõi hơn, nhưng nó sẽ hoạt động, miễn là bạn có PHP> = 5.3.

+24

Điều này làm cho đôi mắt của tôi b̢̗̫͕l͓̫͈e҉͍̖͙ḙ̣̭̦̫̞͟d̼. Tôi sẽ không downvote nó, bởi vì bạn đã cảnh báo anh ta rằng loại mã hóa sẽ không dễ dàng cuộc sống của mình, và nó là hữu ích. Nhưng vẫn: < –

+10

@lonesomeday Up bỏ phiếu chỉ vì bạn có kiên nhẫn để viết ra mã mà khá nhiều không có sử dụng hữu hình! chưa trả lời câu hỏi :-) –

+3

@Truth Có. Nó nên là "bạn có thể làm điều này, nhưng bạn *** thực sự không nên." – lonesomeday

3

Không, bạn không thể có hai phương pháp có cùng tên. Bạn có thể làm cơ bản cùng một điều bằng cách đổi tên một trong các phương pháp. Đổi tên test::send("Hello World!"); thành test::sendMessage("Hello World!"); sẽ hoạt động. Tôi sẽ chỉ tạo một phương thức gửi đơn với một đối số văn bản tùy chọn để thay đổi cách thức các hàm phương thức.

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

    // Send something 
} 

Tôi can đảm là tại sao bạn cần chức năng tĩnh.

+3

Đổi tên phương pháp tĩnh chắc chắn là cách hợp lý để thực hiện việc này. – lonesomeday

-1

Xin lỗi vì đã gặp phải một chuỗi cũ, nhưng tôi muốn mở rộng câu trả lời của @lonesomeday. (Cảm ơn @lonesomeday cho mẫu mã ban đầu.)

Tôi cũng đã thử nghiệm với điều này là tốt, nhưng không muốn gọi các phương pháp như ông gọi chúng trong bài gốc. Thay vào đó tôi có những điều sau đây, mà dường như làm việc:

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

Tôi đồng ý rằng điều này cần phải tránh bằng mọi giá nhưng có một số trường hợp nó có thể có ích.

Trong hầu hết các trường hợp, nó sẽ chỉ làm cho mã của bạn không đọc được và không thể quản lý được.

Tin tôi đi, tôi đã đi xuống con đường đó.

Dưới đây là ví dụ về trường hợp sử dụng trong trường hợp vẫn có thể thực tế.

Tôi đang mở rộng lớp Tệp của CakePHP 3.0 làm lớp xử lý tệp mặc định của tôi.

Tôi muốn đặt trong một trình đoán kiểu tĩnh.

Trong một số trường hợp, tôi có tên tệp thay vì tệp thực và một số giả định cần phải được thực hiện trong trường hợp này.(nếu tập tin tồn tại, hãy thử để có được các mime từ nó khác sử dụng extention của tên tập tin được cung cấp)

lần khác nếu tôi thực sự instantiated một đối tượng mặc định mime() phương pháp nên làm việc, nhưng nếu nó không tên tập tin cần phải được trích xuất từ đối tượng và phương thức tĩnh nên được gọi thay thế.

Để tránh nhầm lẫn mục tiêu của tôi là để có được những loại mime bằng cách gọi phương pháp tương tự:

tĩnh:

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

Như đối tượng

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

Đây là lớp mở rộng ví dụ của tôi:

<?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

Tôi sẽ làm cho một lớp ẩn như các nhà xây dựng và gửi lại rằng lớp ẩn bên trong lớp cha mẹ có phương pháp tĩnh bằng phương pháp lớp ẩn:

// 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; 
    } 

} 

Để gọi nó là tĩnh:

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

Để gọi nó là tự động:

0

Có một cách đơn giản hơn nhiều.

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; 
     } 
    } 

} 

Bây giờ bạn có thể dễ dàng làm:

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

hoặc

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

Bạn có thể sử dụng khuôn khổ này để đạt được tất cả những gì bạn mô tả trong câu hỏi.

Các vấn đề liên quan