Я хочу исключить все унаследованные методы из признаков из списка , которые не переопределяются в классе. Итак, как узнать, унаследован ли элемент класса от признака?
Да, я могу проверить это так:
if ($trait->hasMethod($methodName) || $ref->getTraitAliases()[$methodName] !== null) { // } Но что, если метод признака переоценивается в классе? Как это знать? Один из способов – проверить, схожи ли тела метода, если да, я могу исключить его, но есть ли лучший способ достичь этого?
Важные заметки
Это происходит только из-за «академического» интереса, в реальной ситуации вам не следует заботиться – откуда был получен метод, поскольку он противоречит идее признаков, например, прозрачной замены.
Кроме того, из-за того, как черты работают, любые подобные манипуляции могут считаться «хакерскими», поэтому поведение может различаться в разных версиях PHP, и я бы не стал полагаться на это.
Различие: трудности
  В отражении для PHP есть методы getTraits() которые возвращают экземпляр ReflectionClass , указывая на отражение признака.  Это можно использовать для извлечения всех методов, объявленных в свойствах, которые используются в классе.  Однако – нет, это не поможет в вашем вопросе, поскольку не будет возможности отличить, какие методы были тогда переопределены в классе. 
  Представьте, что есть свойство X с методами foo() и bar() и есть класс Z с помощью метода bar() .  Затем вы сможете узнать, что методы foo() и bar() объявлены в признаке, но если вы попытаетесь использовать getMethods() в классе Z вы, очевидно, получите как foo() и bar() .  Поэтому прямо вы не можете отличить этот случай. 
Различие: work-aroud
Однако, да, есть способ все еще заставить его работать. Первый способ – как вы уже упоминали, – попытаться исследовать исходный код. Это довольно уродливо, но в самом конце это единственный надежный способ решения проблемы на 100%.
  Но – нет, есть другой, «менее уродливый» способ – проверять экземпляры классов ReflectionMethod , которые создаются для методов класса / признаков.  Бывает, что PHP будет использовать один и тот же экземпляр для метода trait, но переопределит тот, который предназначен для метода, объявленного в классе. 
  Эта «проверка» может быть выполнена с помощью spl_object_hash() .  Простая настройка: 
 trait x { public function foo() { echo 'Trait x foo()'; } public function bar() { echo 'Trait x bar()'; } } class z { use x; public function foo() { echo 'Class foo()'; } } 
И теперь, чтобы получить хэши для обоих случаев:
 function getTraitMethodsRefs(ReflectionClass $class) { $traitMethods = call_user_func_array('array_merge', array_map(function(ReflectionClass $ref) { return $ref->getMethods(); }, $class->getTraits())); $traitMethods = call_user_func_array('array_merge', array_map(function (ReflectionMethod $method) { return [spl_object_hash($method) => $method->getName()]; }, $traitMethods)); return $traitMethods; } function getClassMethodsRefs(ReflectionClass $class) { return call_user_func_array('array_merge', array_map(function (ReflectionMethod $method) { return [spl_object_hash($method) => $method->getName()]; }, $class->getMethods())); } 
  Короче говоря, он просто извлекает все методы из атрибута класса (первая функция) или самого класса (вторая функция), а затем объединяет результаты, чтобы получить key=>value карту key=>value где ключ – хэш объекта, а значение – имя метода. 
Тогда нам нужно использовать это в том же экземпляре, как это:
 $obj = new z; $ref = new ReflectionClass($obj); $traitRefs = getTraitMethodsRefs($ref); $classRefs = getClassMethodsRefs($ref); $traitOnlyHashes = array_diff( array_keys($traitRefs), array_keys($classRefs) ); $traitOnlyMethods = array_intersect_key($traitRefs, array_flip($traitOnlyHashes)); 
  Таким образом, $traitOnlyMethods будет содержать только те методы, которые получены из свойства. 
  Соответствующая скрипка здесь .  Но обратите внимание на результаты – они могут отличаться от версии к версии, как в HHVM, она просто не работает (я предполагаю, что из-за того, как реализована реализация spl_object_hash – в любом случае, небезопасно полагаться на нее для разграничения объектов – см. документацию для функции). 
Итак, TD; DR; – да, это может быть (каким-то образом) выполнено даже без разбора исходного кода, но я не могу представить, почему это необходимо, так как черты предназначены для замены кода в классе.
Прошу прощения, но принятый ответ Алмой До совершенно не прав .
  Это решение не может работать, даже если вы преодолеете проблему перераспределения значений spl_object_hash ().  Эта проблема может быть решена путем рефакторинга функций get*MethodRefs() в одну функцию, которая вычисляет оба результата и гарантирует, что объекты ReflectionMethod для методов признаков все еще существуют, когда аналогичные объекты для методов класса создаются.  Это предотвращает повторное использование значений spl_object_hash (). 
  Проблема в том, что предположение о том, что «PHP будет использовать один и тот же экземпляр для метода признаков», является полностью ложным, и появление этого события было вызвано именно «удачной» утилитой spl_object_hash ().  Объект, возвращаемый $traitRef->getMethod('someName') всегда будет отличаться от объекта, возвращаемого $classRef->getMethod('someName') , и поэтому будут соответствующие экземпляры ReflectionMethod в коллекциях, возвращаемых ->getMethods() , независимо от того, переопределен ли метод someName() в классе или нет.  Эти объекты будут не только отличными, они даже не будут «равны»: экземпляр ReflectionMethod полученный из $traitRef будет иметь имя признака как значение его свойства class , а тот, который получен из $classRef будет иметь имя класса. 
Сценарий: https://3v4l.org/CqEW3
Казалось бы, тогда только подходы, основанные на парсерах, жизнеспособны.
  Более простой способ сделать это – ReflectionMethod::getFileName() .  Это вернет имя файла, а не класс. 
  Для экзотического случая, когда trait и class находятся в одном файле, можно использовать ReflectionMethod::getStartLine() , и сравнить это с начальной и конечной строкой признаков и класса. 
Для экзотического случая, когда черта, класс и метод все в одной строке .. о, пожалуйста!