Тег PHPDoc для подавления предупреждений о вызовах динамических функций

у нас есть проект cakePHP, и мы используем класс Path для создания динамических ссылок.

Пример:

$this->redirect(Path::action_my_controller_path($id));

Будет перенаправлять на действие action класса MyController и обрабатывать параметр $id.

Так что теперь моя IDE (PHPStorm) всегда жалуется на отсутствующие функции в Path-классе, так как нет указанной action_my_controller_path($id)-функции.

Кто-нибудь знает об аннотации PHP-Doc для подавления этих сообщений?

edit: после «разговора» с LazyOne через комментарии я добавил следующий PHPDoc в класс Path, как описано в его ссылке ( phpDocumentor ):

 /**
 *
 * @method array|string callStatic(string $name, string $args)
 */

class Path extends Object 

Но я все равно получаю предупреждение при вызове моего класса Path (см. пример выше). Автоматически сгенерированный phpDoc (из моей IDE) для этого метода:

/**
 * @param $name
 * @param $args
 *
 * @return array|string
 */
public static function __callStatic($name, $args){

если я напишу

 /**
 *
 * @method array|string __callStatic(string $name, string $args)
 */

class Path extends Object 

Я получаю Method with same name already defiend in class-ошибку :/

edit2: Полный Path-класс

<?php

/**
 * Zentrale Klasse fuer die Pfade, wobei jede Methode eines der akzeptierten
 * Formate von Router#url zurueckgibt, damit Router#url diese dann in eine
 * URL (als String) umwandeln kann.
 *
 * h3. Benutzung im View:
 *
 * <pre>
 *   $url = Path::alliances_path();
 *   $Html->link($url);
 * </pre>
 *
 *
 * h3. Konventionen (ueber __callStatic umgesetzt):
 *
 * <pre>
 * Semantische URL          <- Methoden Aufruf
 * -----------------------------------------------------------
 * /alliances               <- Path::alliances_path()
 * /alliances/add           <- Path::new_alliance_path()
 * /alliances/view/:id      <- Path::show_alliance_path($id)
 * /alliances/edit/:id      <- Path::edit_alliance_path($id)
 * /alliances/delete/:id    <- Path::delete_alliance_path($id)
 * </pre>
 *
 * h4. Allgemein:
 *
 * Wenn wir direkt eine Entitaet (ueber eine id gegeben) ansprechen, so
 * muss der controller im Singular sein.
 *
 * <pre>
 * /:controller/:action/:id <- Path::`:action:`_`:controller:`_path($id)
 * `:controller:` muss im Singular sein
 * </pre>
 *
 * Wenn wir ueber alle Entitaeten reden bzw. keine spezifische Entitaet
 * ansprechen, dann muss der controller im Plural stehen.
 *
 * z.B. die Uebersicht von `alliances`
 * <pre>
 * /alliances               <- Path::alliances_path($id)
 * </pre>
 *
 * z.B. Custom Actions, die noch keine Entitaet kennen
 * <pre>
 * /accounts/register       <- Path::register_accounts_path()
 * </pre>
 *
 * z.B. Custom Actions mit ohne spez. Entitaet und named parameters
 * <pre>
 * /accounts/register/confirmation:done   <- Path::register_accounts_path(array('confirmation' => 'done'))
 * </pre>
 *
 * h4. Custom Actions:
 *
 * z.B. `kick` Action in AlliancesController
 * <pre>
 * /alliances/kick/:id      <- Path::kick_alliance_path($id)
 * </pre>
 *
 * oder
 *
 * z.B. `leave` in AlliancesController
 * <pre>
 * /alliances/leave/:id     <- Path::leave_alliance_path($id)
 * </pre>
 *
 * h4. Named Parameters:
 *
 * <pre>
 * /alliances/sort:user_id/order:asc  <- Path::alliances_path(array('sort' => 'user_id', 'order' => 'asc'))
 * /alliances/kick/:id/user:600001    <- Path::kick_alliance_path($id, array('user' => 600001))
 * </pre>
 *
 * @see http://book.cakephp.org/2.0/en/development/routing.html#named-parameters
 */
class Path extends Object {

  /** @const */
  const LOGIN_PATH  = '/auth/login';
  const LOGOUT_PATH = '/auth/logout';
  const WELCOME_PATH = '/welcome';

  public static $settings = array(
    'signup' => array(
        'singular' => true,
        'plugin' => false,
        'entityActions' => array('disabled', 'world', 'code_expired', 'confirmation', 'disallowed', 'resend') # must be underscored
      ),
    'recover' => array(
        'singular' => true,
        'plugin' => false,
        'entityActions' => array('account', 'verify', 'token_expired')
      ),
    'support' => array(
        'singular' => true,
        'plugin' => false,
        'entityActions' => array('banned')
      ),
    'contact' => array(
        'singular' => true,
        'plugin' => false
      ),
    'about' => array(
        'singular' => true,
        'plugin' => false
      ),
    'auth' => array(
        'singular' => true,
        'plugin' => false,
        'entityActions' => array('counselor')
      ));



  public static function parseUrl($url) {
    $url = Router::normalize($url);
    $request = new CakeRequest($url, false);

    $params = Router::parse($request->url);
    $request->addParams($params);

    return $request;
  }

  protected static function getId($id){
    // ist kein array, muss id sein
    if(!is_array($id)) {
      return $id;
    }

    // id column vorhanden! als id nehmen
    if(isset($id['id'])) {
      return $id['id'];
    }

    trigger_error('Path: missing id column', E_USER_NOTICE);
    return null;
  }

  /* extract first argument to support:
   * - edit_user_path(1);
   * - edit_user_path(array(1));
   * - edit_user_path(array('id' => 1));
   * url will be /users/edit/1
   *
   * to suport named parameters use second array
   * - edit_user_path(1, array('key' => 'value'))
   * url will result as /users/edit/1/key:value
   */
  /**
   * @param      $args
   * @param bool $requires_id
   *
   * @return array
   */
  protected static function extractOptions($args, $requires_id = false){

    // keine argumente vorhanden
    if(!isset($args[0])) {
      return array();
    }

    // setzen von named parameters
    if($requires_id) {
      $named_parameters = isset($args[1]) && is_array($args[1]) ? $args[1] : array();
    } else {
      $named_parameters = is_array($args[0]) ? $args[0] : array();
    }

    // /alliances/index/name:parameter
    // -> hat keinen index, darum nur die
    // named_paramerters zurueck geben
    if(!$requires_id) {
      return $named_parameters;
    }

    // id muss vorhanden sein!, da kein index
    $id = self::getId($args[0]);
    return array_merge($named_parameters, array($id));
  }

  /**
   * @param $name
   * @param $args
   *
   * @return array|string
   */
  public static function __callStatic($name, $args){
    $parts = explode('_', $name);
    $path_or_url = array_pop($parts);

    # convert path into url
    if($path_or_url === 'url') {
      $name = implode('_', $parts) . '_path';

      # custom paths have priority over general
      $url  = call_user_func_array('static::' . $name, $args);
      return h(Router::url($url, true));
    }

    # neither path nor url
    if($path_or_url !== 'path') {
      return parent::__callStatic($name, $args);
    }

    if(count($parts) == 1) {
      # the short syntax
      $action = 'view';
      $controller_raw = $parts[0];
    } else {
      # first part is always the action
      $action = array_shift($parts);
      # for Path::action_complex_controller_path syntax we have to join
      $controller_raw = implode('_', $parts);
    }

    # underscore controller and action
    $action         = Inflector::underscore($action);
    $controller_raw = Inflector::underscore($controller_raw);

    $settings = isset(static::$settings[$controller_raw]) ?
                      static::$settings[$controller_raw] : array();

    # alias for more descriptive actions
    if($action === 'show') {
      $action = 'view';
    }else if($action === 'new') {
      $action = 'add';
    }

    # if the controller is in singular
    if(isset($settings['singular']) && $settings['singular']) {
      $controller = $controller_raw;
      $no_entity_path = true;
    } else {
      $controller = Inflector::pluralize($controller_raw);
      $no_entity_path = $controller == $controller_raw;
    }

    $is_index_path = $action == 'view' && $no_entity_path;

    # if the controller is in plural, then it is no entitiy
    $is_entity_path = (!$no_entity_path && $action != 'add') || in_array($action, (array)$settings['entityActions']);

    $defaults = array(
      'controller' => $controller,
      'action' => $is_index_path ? 'index' : $action,
      'plugin' => (boolean)$settings['plugin']
    );

    $options = static::extractOptions($args, $is_entity_path);

    return array_merge($defaults, $options);
  }
}

person bish    schedule 21.08.2014    source источник
comment
Вы пробовали Alt + Enter при ошибке? В любом случае: вы можете понизить серьезность этой проверки (у нее есть несколько вариантов) ... или даже полностью отключить эту проверку (при желании).   -  person LazyOne    schedule 21.08.2014
comment
Alt+Enter добавляет недостающую функцию, но мне это не нужно, так как Path-класс генерирует ссылку через regEx. Я также не хочу отключать или снижать серьезность проверки missing function, так как я хочу подавить ее только в классе Path, но не в других классах. В любом случае спасибо LazyOne   -  person bish    schedule 21.08.2014
comment
1) Покажите скриншот вашего меню Alt+Enter — похоже, вы не знаете, какие еще функции оно имеет/может выполнять; 2) Вы можете снизить серьезность для случаев, когда такой класс имеет магические __call/__callStatic методы - только ваш случай. Вы проверили, какие варианты есть у инспекции .. или это было просто я не проверял, но я думаю... момент?   -  person LazyOne    schedule 21.08.2014
comment
1) Я думаю, вы намерены подавить этот вариант утверждения? Это почти то, что мне нужно, но я хотел бы иметь глобальное подавление, которое я мог бы определить в классе Path. Если это не сработает, я должен спамить свой код опцией подавления этого оператора: / 2) Я знаю, что могу снизить серьезность для методов магического вызова. Но мне нравится получать предупреждение, когда метод не найден, кроме класса Path.   -  person bish    schedule 21.08.2014
comment
Отлично -- хорошо, что вы знаете обо всех этих моментах (сейчас?). Если бы вы были о них раньше -- вы бы сразу упомянули о них, чтобы мне не пришлось задавать эти вопросы/писать их в такой манере. В любом случае: Этот ваш Path класс -- он действительно ваш (я имею в виду -- вы можете свободно его модифицировать) или он является частью какой-то структуры, которую вы не можете трогать?   -  person LazyOne    schedule 21.08.2014
comment
Да, я упомянул об этом более ясным образом. Класс Path написан моей командой, поэтому я могу свободно его модифицировать.   -  person bish    schedule 21.08.2014
comment
Прохладный. Используйте тег @method в комментарии PHPDoc для этого класса Path -- github.com/phpDocumentor/fig-standards/blob/master/proposed/   -  person LazyOne    schedule 21.08.2014
comment
Я отредактировал свой пост, чтобы показать результаты @method   -  person bish    schedule 22.08.2014
comment
Вы хотите, чтобы PhpStorm перестал жаловаться на отсутствие метода action_my_controller_path()... тогда почему вместо этого вы описываете __callStatic() :)? Вы должны сделать @method static string action_my_controller_path(int $id) или как там этот метод объявлен. P.S. Не уверен на 100%, куда должен идти static -- до или после возвращаемого типа (string в моем примере выше)   -  person LazyOne    schedule 22.08.2014
comment
Как упоминалось в моем начальном посте, метод не существует и никогда не будет существовать, потому что URL-адрес динамически извлекается через __callStatic(). Я добавил полный класс Path, чтобы вы поняли, что я имею в виду. Также посмотрите примеры в комментариях, если вы все еще не поняли, что я имею в виду под динамически извлекаемыми.   -  person bish    schedule 22.08.2014
comment
1) :) Это не динамически извлекаемый метод $this->redirect(Path::action_my_controller_path($id)); -- вы вызываете action_my_controller_path() НЕПОСРЕДСТВЕННО. 2) Неважно, как оно будет выполняться за кулисами (динамически извлекаться из имени или браться из какой-то карты (это имя будет выполнять это действие и т. д.) .. или даже передаваться родительскому класс/связанный класс для выполнения. Все дело в том, чтобы вызывать его НЕПОСРЕДСТВЕННО в вашем коде. И для этого предназначен @method.   -  person LazyOne    schedule 22.08.2014


Ответы (1)


Если вы хотите, чтобы PhpStorm перестал жаловаться на доступ к методу action_my_controller_path() (или любому другому КОНКРЕТНОМУ методу), используйте @method для его объявления:

ДО:

введите здесь описание изображения

ПОСЛЕ:

введите здесь описание изображения

Вам не нужно объявлять каждый метод — только те, которые вы планируете вызывать НЕПОСРЕДСТВЕННО, как вы сделали здесь: $this->redirect(Path::action_my_controller_path($id));


Если вы хотите, чтобы PhpStorm перестал жаловаться на доступ к ЛЮБОМ несуществующему методу, вы ничего не можете с этим поделать, потому что вы отказались от использования всех доступных на данный момент вариантов для такого случая:

  • Снижение серьезности для доступа к несуществующим методам, когда доступны магические __call/__callStatic .. или полное отключение этой проверки (последнее может быть излишним, я согласен);
  • Параметр "Suppress for statement" для подавления предупреждений в этом конкретном месте.

К сожалению, нет доступного синтаксиса @method, где вы можете использовать подстановочные знаки, например. @method static array *(int $id);.

person LazyOne    schedule 22.08.2014
comment
Если весь ваш текст выделен, ничего не будет. - person halfpastfour.am; 25.06.2015