What is polymorphism and what are its main types?

I'm starting out as a programmer. They told me to learn polymorphism. I started reading from different sources, but it is not completely clear everywhere. I understand this very broad concept that there are 3 main types and each of them is divided into many more types.

I will just write how I understood from what I read and from what my friend suggested. Please correct me if I made a mistake. I will be glad if you describe briefly what it is and the 3 main types.

I understand there are 3 main types of polymorphism (examples in php):

  1. Ad hoc polymorphism - multiple function declarations with the same name but different parameters, example:

When calling the function, the one that corresponds to the argument type is selected.

function test (string $a, string $b) {
    return $a . $b;
}
function test (int $a, int $b) {
    return $a + $b;
}

// если бы в пхп поддерживалось, то вывело бы
test('a', 'b') // 'ab'
test(1, 4) // 5
  1. Parametric polymorphism - when the same function is executed regardless of the argument types.

It is supported in php.

function test (string $a, string $b) {
    return $a . $b;
}
function test (int $a, int $b) {
    return $a + $b;
}

// если бы в пхп поддерживалось, то вывело бы
test('a', 'b') // 'ab'
test(1, 4) // 5

Parametric polymorphism is a true form of polymorphism, making the language more expressive and significantly increasing the code reuse rate. Traditionally, it is opposed to Ad hoc polymorphism (imaginary form).

  1. Subtype polymorphism - as far as I understand this is the most popular concept of polymorphism.

This is when there are methods in different classes that do the same thing, they should be given the same name and make these classes implement a single interface or inherit a single abstract class with this abstract method.


It is still a little unclear what the Subtype associated with interfaces is when the other two are associated with parameters and Parametric is true, and Ad hoc is its imaginary form as I read.

Author: Саша Егоров, 2018-10-27

1 answers

Honestly not strong in modern terms, but earlier what you have given:

Ad hoc polymorphism

Parametric polymorphism

It was called "function/method overloading". As for

Subtype polymorphism

This is really important today. What is the point - in the comments they gave a good link to the article. But it's not cool when inanimate examples are given for training: you won't see this in PHP.

And here are the examples that I I will add: I see it in PHP every day, and I think they will help to reveal the essence of this concept. The database of almost every site has users, articles, and photos. For universal work with DB series, there is a pattern ActiveRecord, which polyformism uses most explicitly. For example, there are classes that describe rows in the database:

class User extends ActiveRecord
class Article extends ActiveRecord
class Photo extends ActiveRecord

The ActiveRecord itself has on-board methods save() , setFromArray(), getId() . Examples of how to work with ActiveRecord - s:

//1
$user = new User(1234);//получение юзера с id=1234 из БД
$user->first_name = 'Евпатий';
$user->save();

//2
$article = new Article(1234);
$article->setFromArray($formdata);
$article->save();
echo('Article '. $article->getId(). ' saved');

For example, before saving a specific article, we want to make a trigger, and reset the cache, to do this, we extend the behavior of the save:

class Article extends ActiveRecord
{
...
public function save()
{
 $this->resetSomeArticleCache();
 return parent::save();
}
}

Thus, somewhere in the code, there may be a universal controller whose task is to update a certain field that many records have:

public function upgradeModifyDateAction()
{
  $type = $_GET['type'];
  $id = (int)$_GET['id'];
  //полиморфное получение ряда тут максимально наглядно описано, обычно это как-то Core::getRow($type, $id) 
  if (is_subclass_of($type, 'ActiveRecord') 
      && ($row = new $type($id)) 
      && $row->isExists()
      && $row->fieldExists('modify_date')
  ){
     $row->modify_date = date('Y-m-d H:i:s');
     $row->save();// !! полиформизм здесь !!
  }else{/*ошибка*/}
}

The bottom line is that the controller doesn't really care which particular ActiveRecord it was asked to update, and if the object has a "special behavior" to update, then it will execute: that is, the resetSomeArticleCache method is called for the article in the example. In this case, a special behavior transparent to the controller - that's the point.

The main point is to save the programmer's memory when using polymorphism: imagine that there are not 3, but 100 different ActiveRecords in the system. To work with one of these objects (or a group), you do not need to remember either the name of the table in which it is stored, or the name of the id column, you do not need to think about whether the list of objects is homogeneous before running it in a loop: just remember that there is a method getId() that will return the id, and there is a method save() - which will save the object in the database.

As well as not to think about the fact that "so, and if I update the article in the code - I also need to clean the cache", insert unnecessary if - s. Therefore, it is important - it is easier to live with polymorphism, it is impossible to say that this is something special, today this concept is generally inseparable from inheritance in any modern systems. languages.

Speaking about the types of polymorphism, PHP often still uses "duck polymorphism " - some believe this antipattern, and some praise. For me, it is moderately useful:

/*например функция проверки прав $user на $object*/
public function checkRights($user, $object, $right = 'edit')
{
  ...
  if (method_exists('isExtraAllowed', $object)){
   if (($result = $object->isExtraAllowed($user, $right)) != self::IGNORE)
    return $result;
  }
  ...
}

In the example, the fact is that it would be blasphemous to start the basic f-y isExtraAllowed in ActiveRecord, since ActiveRecord does not belong to rights in principle - and we will smear a clear class for ourselves. And the need to add such a utino-polymorphic insert as isExtraAllowed always arises in real projects in my memory (where, of course, OOP is widely used), especially if the ACL rights system was introduced far after the beginning the project.
Yes, in the example, instead of the duck approach, you could add an interface by naming it to for example IACLExtendedProvider, but first, this will clog the global list of classes and interfaces(and the programmer's brain at the same time), and secondly, a programmer who is not used to interfaces will enter a stupor when he does not understand why the method isExtraAllowed added by him does not work.

 1
Author: Гончаров Александр, 2020-06-12 12:52:24