PHP – 有可能声明一个方法是静态的和非静态的
我可以在一个对象中声明一个方法作为一个静态方法和非静态方法,它们具有相同的名称来调用静态方法吗?
我想创build一个具有静态方法“发送”的类和一个调用静态函数的非静态方法。 例如:
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 } }
我希望能够调用这两个函数
test::send("Hello World!");
和
test::instance()->setText("Hello World")->send();
可能吗?
你可以做到这一点,但有点棘手。 你必须重载: __callStatic
和__callStatic
魔术方法。
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]); } } }
这不是一个理想的解决scheme,因为它使得你的代码更难以遵循,但是它会工作,只要你有PHP> = 5.3。
不,你不能有两个同名的方法。 你可以通过重命名其中一个方法来做基本相同的事情。 重命名test::send("Hello World!");
test::sendMessage("Hello World!");
会工作。 我只是用一个可选的文本参数创build一个单一的发送方法,改变方法的function。
public function send($text = false) { if (!$text) { $text = $this -> text; } // Send something }
对于你为什么需要静态function,我感到很高兴。
对不起,因为碰到了一个旧的线程,但是我想在@lonesomeday的答案上进一步说明。 (感谢@lonesomeday为最初的代码示例。)
我也在试验这个,但是不想在原来的post中打电话给他们。 相反,我有以下, 似乎工作:
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( 'foo@foo.foo' ); $Emailer = new Emailer; $Emailer->to( 'bar@bar.bar' ); $Emailer->send();
我同意不惜一切代价避免这种情况,但在某些情况下可能有用。
在大多数情况下,它会让你的代码不可读,难以pipe理。
相信我,我已经走下了这条路。
这是一个用例情景,可能仍然是实用的。
我正在扩展CakePHP 3.0的File类作为我的默认文件处理类。
我想要一个静态的mimetypes的猜测。
在某些情况下,我有一个文件名而不是实际的文件,在这种情况下需要做一些假设。 (如果文件存在,尝试从其中获取MIME,否则使用扩展名提供的文件名)
其他时候,如果我实际上实例化一个对象的默认mime()方法应该工作,但如果它失败的文件名需要从对象中提取,而应该调用静态方法。
为了避免混淆,我的目标是通过调用相同的方法来获得mimetypes:
静态的:
NS\File::type('path/to/file.txt')
作为对象
$f = new NS\File('path/to/file.txt'); $f->type();
这是我的示例扩展类:
<?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; } }
我将创build一个隐藏的类作为构造函数,并返回隐藏的类内的父类的静态方法等于隐藏的类方法:
// 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; } }
要静态调用它:
Hook::on("click", function() {});
要dynamic调用它:
$hook = new Hook; $hook->on("click", function() {});