Intereting Posts
Почему MySQL не поддерживает миллисекундную / микросекундную точность? codeigniter 2 и как отключить xss для TinyMCE Как использовать ACL для фильтрации списка объектов домена в соответствии с разрешениями определенного пользователя (например, EDIT)? PHP перестроение изображений: использование памяти php shell_exec touch redirect и adduser Crypto-Js отличается от mcrypt PHP – «print / echo», отображающий закрывающие теги – или не выводит Чтение данных из текстового файла и формирование таблицы с использованием php как передать значение с одной php-страницы на другую, используя сеанс Как получить значения блока checkbox в Laravel 5? Как подключить кодер паролей к пользовательскому интерфейсу в Silex? Не удается передать соединение mysqli в сеансе в php Google App Engine (php): функция glob () Как выполнить файл Octave с помощью php Laravel Eloquent whereRaw sql возвращает все строки при использовании оператора OR

PHP – можно ли объявить метод статическим и нестатическим

Могу ли я объявить метод в объекте как статический и нестатический метод с тем же именем, который вызывает статический метод?

Я хочу создать класс, который имеет статический метод «Отправить» и нестатический метод, который вызывает статическую функцию. Например:

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(); 

Является ли это возможным?

Вы можете это сделать, но это немного сложно. Вы должны сделать это с перегрузкой: __call и __call .

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

Это не идеальное решение, так как это делает ваш код более сложным, но он будет работать, если у вас есть PHP> = 5.3.

Нет, у вас не может быть двух методов с тем же именем. Вы можете сделать одно и то же, переименовав один из методов. Переименование test::send("Hello World!"); для test::sendMessage("Hello World!"); должно сработать. Я бы просто создал единственный метод отправки с необязательным текстовым аргументом, который изменяет способ работы метода.

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

Я волнуюсь, почему вам нужна статическая функция вообще.

Я бы сделал скрытый класс конструктором и возвратил этот скрытый класс внутри родительского класса, который имеет статические методы, равные методам скрытого класса:

 // 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() {}); 

Чтобы назвать его динамически:

 $hook = new Hook; $hook->on("click", function() {}); 

Это гораздо проще.

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

Теперь вы можете легко сделать:

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

или

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

Вы можете использовать эту структуру для достижения всего, что вы описали в вопросе.

Извините за столкновение старой темы, но я хотел бы расширить ответ на @lonesomeday. (Спасибо @lonesomeday за исходный образец кода.)

Я тоже экспериментировал с этим, но не хотел называть методы, как он их называл в оригинальной записи. Вместо этого у меня есть следующее, которое, похоже, работает:

  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(); 

Я согласен с тем, что этого следует избегать любой ценой, но есть случаи, когда это может быть полезно.

В большинстве случаев он просто сделает ваш код нечитаемым и неуправляемым.

Поверь мне, я был на том пути.

Вот пример сценария использования, где он может быть практически практичным.

Я расширяю класс файлов CakePHP 3.0 как мой класс обработки файлов по умолчанию.

Я хотел, чтобы вставлял статичный гаджет типа mime.

В некоторых случаях у меня есть имя файла вместо фактического файла, и в этом случае необходимо сделать некоторые предположения. (если файл существует, попробуйте получить от него mime, используйте расширение extename)

В других случаях, если я фактически создавал экземпляр объекта, метод mime () по умолчанию должен работать, но если он не удается, имя файла необходимо извлечь из объекта, и вместо него следует вызвать статический метод.

Чтобы избежать путаницы, моя цель состояла в том, чтобы получить тип mime, вызвав тот же метод:

Статическая:

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