Преобразование типа для определяемых пользователем объектов

Этот раздел документации может помочь вам https://symfony.com/doc/master/bundles/SonataAdminBundle/reference/form_types.html использовать SonataAdminBundleFormTypeModelAutocompleteType. Поскольку ваш вопрос трудно понять из-за отсутствия контекста, вас также может заинтересовать https://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/filter_field_definition.html [ 111] doctrine_orm_model_autocomplete.

51
задан Charles 23 December 2012 в 10:27
поделиться

6 ответов

Нет необходимости вводить приведение в php.


Изменить: Поскольку эта тема, кажется, вызывает некоторую путаницу , Я подумал, что я немного уточню.

В таких языках, как Java, есть две вещи, которые могут нести тип. Компилятор имеет представление о типах, а среда выполнения имеет другое представление о типах. Типы компиляторов привязаны к переменным, тогда как механизм времени выполнения отслеживает тип значений (которые присваиваются переменным). Типы переменных известны во время компиляции, тогда как типы значений известны только во время выполнения.

Если часть входного кода нарушает систему типов компилятора, компилятор заблокирует и остановит компиляцию. Другими словами, невозможно скомпилировать фрагмент кода, нарушающий систему статических типов. Это отлавливает определенный класс ошибок. Например, возьмите следующий фрагмент (упрощенного) Java-кода:

class Alpha {}

class Beta extends Alpha {
  public void sayHello() {
    System.out.println("Hello");
  }
}

Если бы мы сейчас сделали это:

Alpha a = new Beta();

, все было бы хорошо, поскольку Beta является подклассом Alpha , и, следовательно, допустимое значение для переменной a типа Alpha . Однако, если мы продолжим:

a.sayHello();

Компилятор выдаст ошибку, поскольку метод sayHello не является допустимым методом для Alpha - несмотря на то, что мы знаем, что a на самом деле является Beta .

Введите приведение типа:

((Beta) a).sayHello();

Здесь мы сообщаем компилятору, что переменная a должна - в данном случае - рассматриваться как бета . Это называется приведением типа. Эта лазейка очень полезна, потому что допускает полиморфизм в языке, но, очевидно, также является лазейкой для всевозможных нарушений системы типов. Поэтому для обеспечения некоторой безопасности типов существуют некоторые ограничения; Вы можете приводить только к связанным типам. Например. вверх или вниз по иерархии. Другими словами, вы не сможете выполнить приведение к совершенно несвязанному классу Чарли .

Важно отметить, что все это происходит в компиляторе - то есть это происходит еще до того, как код будет запущен . Java все еще может попадать в ошибки типа времени выполнения. Например, если вы сделали это:

class Alpha {}

class Beta extends Alpha {
  public void sayHello() {
    System.out.println("Hello");
  }
}

class Charlie extends Alpha {}

Alpha a = new Charlie();
((Beta) a).sayHello();

Приведенный выше код действителен для компилятора, но во время выполнения вы Я получу исключение, так как приведение из Бета в Чарли несовместимо.

Тем временем, вернемся к PHP-ферме.

Следующее верно для PHP- компилятор - он с радостью превратит это в исполняемый байт-код, но вы получите ошибку времени выполнения:

class Alpha {}

class Beta extends Alpha {
  function sayHello() {
    print "Hello";
  }
}
$a = new Alpha();
$a->sayHello();

Это потому, что переменные PHP не имеют типа. Компилятор не имеет представления о том, какие типы времени выполнения допустимы для переменной, поэтому он не пытается ее принудительно применить. Вы также не указываете тип явно, как в Java. Да, есть подсказки типа, но это просто контракты времени выполнения. Следующее по-прежнему действует:

// reuse the classes from above
function tellToSayHello(Alpha $a) {
  $a->sayHello();
}
tellToSayHello(new Beta());

Несмотря на то, что переменные PHP не имеют типов, значения по-прежнему имеют. Особый интересный аспект PHP заключается в том, что можно изменять тип значения. Например:

// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
settype($foo, "integer");
echo gettype($foo); // Yields "integer"

Эту функцию иногда путают с приведением типов, но это неправильное название. Тип по-прежнему является свойством значения, и изменение типа происходит во время выполнения, а не во время компиляции.

Возможность изменения типа также весьма ограничена в PHP. Менять тип можно только между простыми типами, но не объектами. Таким образом, невозможно изменить тип с одного класса на другой. Вы можете создать новый объект и скопировать состояние, но изменить тип невозможно. PHP в этом отношении немного посторонний; В других подобных языках классы рассматриваются как гораздо более динамичная концепция, чем в PHP.

Еще одна похожая особенность PHP заключается в том, что вы можете клонировать значение как новый тип, например:

// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
$bar = (integer) $foo;
echo gettype($bar); // Yields "integer"

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

Подводя итог: Приведение типа - это операция, которая изменяет тип переменной ( не значение). Поскольку переменные в PHP не имеют типа, это не только невозможно сделать, но и вообще бессмысленно спрашивать.

100
ответ дан 7 November 2019 в 09:55
поделиться

Мне главным образом нужно преобразование типа для включения intellisense - таким образом, я просто создаю помощника броска типа:

function castToTest($val): Test
{
    return $val;
}
$test = castToTest(require("someFile.php"));

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

0
ответ дан 7 November 2019 в 09:55
поделиться

Вот функция для изменения класса объекта:

/**
 * Change the class of an object
 *
 * @param object $obj
 * @param string $class_type
 * @author toma at smartsemantics dot com
 * @see http://www.php.net/manual/en/language.types.type-juggling.php#50791
 */
function changeClass(&$obj,$new_class)
{
    if(class_exists($class_type,true))
    {
        $obj = unserialize(preg_replace("/^O:[0-9]+:\"[^\"]+\":/i",
            "O:".strlen($class_type).":\"".$new_class."\":", serialize($obj)));
    }
}

В случае непонятно, это не моя функция, это было взято из сообщения "toma at smartsemantics dot com" на http://www.php.net/manual/en/language.types.type-juggling. php # 50791

7
ответ дан 7 November 2019 в 09:55
поделиться

Я не верю, что в PHP есть оператор перегрузки, чтобы справиться с этим, однако:

<?php

class MyClass {

  protected $_number;

  static public function castFrom($obj) {
    $new = new self();
    if (is_int($obj)) {
      $new->_number = $obj;
    } else if ($obj instanceOf MyNumberClass){
      /// some other type of casting
    }
    return $new;
  }
}

$test = MyClass::castFrom(123123);
var_dump($test);

Это один из способов справиться с этим.

1
ответ дан 7 November 2019 в 09:55
поделиться

Я переработал функцию, которую опубликовал Джош (которая выдает ошибку из-за неопределенной переменной $ new_class). Вот что у меня получилось:

function changeClass(&$obj, $newClass)
{   $obj = unserialize(preg_replace // change object into type $new_class
    (   "/^O:[0-9]+:\"[^\"]+\":/i", 
        "O:".strlen($newClass).":\"".$newClass."\":", 
        serialize($obj)
    ));
}

function classCast_callMethod(&$obj, $newClass, $methodName, $methodArgs=array())
{   $oldClass = get_class($obj);
    changeClass($obj, $newClass);

    // get result of method call
    $result = call_user_func_array(array($obj, $methodName), $methodArgs);
    changeClass(&$obj, $oldClass);  // change back
    return $result;
}

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

Бо всем придуркам, которые говорят, что «php не выполняет преобразование» или "не нужно вводить php". Буллхоккей. Приведение типов - важная часть объектно-ориентированной жизни, и я хотел бы найти лучший способ сделать это, чем уродливые хаки сериализации.

Так что спасибо, Джош!

7
ответ дан 7 November 2019 в 09:55
поделиться

Я думаю, что для того, чтобы сделать лучшую IDE, нужно набирать cast. Но сам язык php не нуждается в приведении типов, однако он поддерживает изменение типов значений переменных во время выполнения. Посмотрите на autoboxing и unboxing. Это то, что php делает по своей природе. Так что, извините, не лучше, чем уже есть IDE.

1
ответ дан 7 November 2019 в 09:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: