Error PHP POO polymorphism

While developing a simple PHP POO application, I came across an unexpected error, and that I have no idea why. I am now starting to study Object-Oriented Programming and only have a small base in C#.

The program itself is simple: two classes (Pessoa and Funcionario) being Funcionario inherited from the Class Pessoa, each with 2 methods, ler() and mostrarDados().

My goal is simple to create an object and reference all the information for Method lerDados() of Class Funcionario, and within this, call method LerDados() of Class Pessoa (parent::lerDados()) passing only relevant class information(nome, idade and sexo), the rest is "read" in the class itselfFuncionario (empresa and salario).

Error: the Declaration of Official::lerDados($stringNome, $stringIdade, $stringSexo, $stringEmpresa, $stringSalario) should be compatible with Person::lerDados($stringNome, $stringIdade, $stringSexo in C:\wamp64\www\POO\namespace1.php on line 31

  <?php
  class Pessoa{     
  // PROPRIEDADES
  protected $nome;
  protected $idade;
  protected $sexo;  
  // METODOS      
   public function lerDados($stringNome, $stringIdade, $stringSexo){
    $this->nome  = $stringNome;
    $this->idade = $stringIdade;
    $this->sexo  = $stringSexo; 
  }  
  public function mostrarDados(){
    return "Nome: ".$this->nome."<br>\nIdade:".$this->idade."
  <br>\nSexo:".$this->sexo;
  }
  } 


  class Funcionario extends Pessoa{ 
  // PROPRIEDADES
  protected $empresa;
  protected $salario;
  // METODOS    
   public function lerDados($stringNome, $stringIdade, $stringSexo, 
   $stringEmpresa, $stringSalario){
     $this->nome  = $stringNome;
     $this->idade = $stringIdade;
     $this->sexo  = $stringSexo; 
     parent:: lerDados($this->nome,$this->idade,$this->sexo); // CHAMAR METODO DAS CLASSE PAI 
     $this->empresa = $stringEmpresa;
     $this->salario = $stringSalario;     
   }
   //public function mostrarDados(){}

   } // <------ERRO NESTA LINHA <-------

   $vendedor = new Funcionario();
   $vendedor->lerDados("Yuri", "19", "Masculino", "Tam", "3000");
   ?>

Am I seriously wrong, or does PHP not accept this kind of polymorphism? Could someone guide me to how to fix this, and answer why this brutally fatal mistake happened?

Author: Maniero, 2017-10-19

2 answers

I often say that if everyone who claims to do OOP did it right, they would give up. OOP adds complexity to the code. If done where needed brings advantages.

I see some problems in this code. First of all, I don't think there's any inheritance in there. There are those who disagree, but I think that being an employee is only a role that the person can have and there is no relationship of is a.

This mostraDados() assumes the use of a specific device to show that it should not be part of of a person or employee. What is data printing should be elsewhere.

Almost always putting protected members is a mistake. There are those who think that languages should not even have this because it is either poorly used or it is to make gambiarra. In general violates the encapsulation. It's either public or it's private. I see reasons to use, but not this one.

And then the lerDados() of the Funcionario got weird because it initializes the protected members and calls the mother class method to initialize again (?!?!?!).

This method does not read any given, so its name is wrong.

Objects should always be created in a valid state , so this should probably be a constructor . Done this way everything will be ok.

Polymorphism occurs with methods of the same signature . So the method of one class is not polymorphic to that of the other. PHP does not have method overhead and therefore prevents two methods with same different name and signature. If the signature was the same then it would be polymorphic and the child class would have only one method with the same name.

Note that this is not exactly the polymorphism even in C# and other languages, the difference is that other languages accept overhead and will allow to have two methods with the same name and non-polymorphic signatures.

Constructors are not polymorphic, they are actually static. So it works:

class Pessoa {     
    private $nome;
    private $idade;
    private $sexo;  
    public function __construct($stringNome, $stringIdade, $stringSexo) {
        $this->nome  = $stringNome;
        $this->idade = $stringIdade;
        $this->sexo  = $stringSexo; 
    }  
} 

class Funcionario extends Pessoa { 
    private $empresa;
    private $salario;
    public function __construct($stringNome, $stringIdade, $stringSexo, $stringEmpresa, $stringSalario) {
        parent::__construct($stringNome, $stringIdade, $stringSexo);
        $this->empresa = $stringEmpresa;
        $this->salario = $stringSalario;     
    }
}

$vendedor = new Funcionario("Yuri", "19", "Masculino", "Tam", "3000");

See working on Ideon. E no repl.it. also I put on GitHub for future reference .

Of course, one day if that same person ceases to be an employee and becomes something else in the organization, you have to kill that person if you do the resurrection as something else. I find that very strange.

If the person can be an employee and something else at the same time, will he have two objects that are basically the same person? If you can be a customer and will the legal person have to differentiate whether the client is physical or legal? What a roll.

When it misconcepts, OOP doesn't save anyone.

When you do OOP just because everyone is doing it, just the way a person said it's right and the mass is copying without understanding why you're doing it is not suitable.

 4
Author: Maniero, 2020-06-23 15:28:57

How we model our classes will depend on the behavior (rules) defined for the application. In the model below I considered that in your application, a person cannot be simply a person (Direct instance of the class), for this reason the constructor of the Class person has been set to protected, that is, it must be called by another class that inherits from person.

If we consider that Name, age and Gender are attributes primary of the class, we can use a constructor and receive this data already at the time we create an instance of the object. To retrieve the values I like to use the getAtributo approach, so I know that this public method is used to retrieve an attribute. The visual processing / formatting can be done by an auxiliary class or can be done directly in the file that calls the method.

See code:

<?php

class Pessoa{     

    private $nome;
    private $idade;
    private $sexo;  

    protected function __construct($nome, $idade, $sexo)
    {
        $this->nome = $nome;
        $this->idade = $idade;
        $this->sexo = $sexo;
    }

    protected function getNome()
    {
        return $this->nome;
    }

    protected function getIdade()
    {
        return $this->idade;
    }

    protected function getSexo()
    {
        return $this->sexo;
    }
} 

class Funcionario extends Pessoa
{ 
    private $empresa;
    private $salario;

    public function __construct($nome, $idade, $sexo, $empresa, $salario)
    {
        parent::__construct($nome, $idade, $sexo);
        $this->empresa = $empresa;
        $this->salario = $salario;
    }

    public function getEmpresa()
    {
        return $this->empresa;
    }

    public function getSalario()
    {
        return $this->salario;
    }
}

$funcionario = new Funcionario("Yuri", "19", "Masculino", "Tam", "3000");

echo $funcionario->getNome() . ' Trabalha na: ' . $funcionario->getEmpresa() . ' e ganha ' . $funcionario->getSalario();

Let's take a second approach. Personally I like to use the famous setAtributo to define the value of my variables, but why do I do this? Simple, to include validation in the assignment of values. The example below is quite simple and does not reflect an actual flow of data validation, but serves to pass an idea of how the thing works:

<?php

class Pessoa{     

    private $nome;
    private $idade;
    private $sexo;  

    protected function setNome($nome)
    {
        if(is_string($nome)) {
            $this->nome = $nome;
            return true;
        }

        return false;
    }

    protected function setIdade($idade)
    {
        if(is_int($idade)) {
            $this->idade = $idade;
            return true;
        }

        return false;
    }

    protected function setSexo($sexo)
    {
        if($sexo == 'M' || $sexo = "F") {
            $this->sexo = $sexo;
            return true;
        }

        return false;
    }

    public function getNome()
    {
        return $this->nome;
    }

    public function getIdade()
    {
        return $this->idade;
    }

    public function getSexo()
    {
        return $this->sexo;
    }
} 

class Funcionario extends Pessoa
{ 
    private $empresa;
    private $salario;

    public function __construct($nome, $idade, $sexo, $empresa, $salario)
    {
        self::setNome($nome);
        self::setIdade($idade);
        self::setSexo($sexo);
        $this->empresa = $empresa;
        $this->salario = $salario;
    }

    public function getEmpresa()
    {
        return $this->empresa;
    }

    public function getSalario()
    {
        return $this->salario;
    }
}

$funcionario = new Funcionario("Yuri", "19", "Masculino", "Tam", "3000");

echo $funcionario->getNome() . ' Trabalha na: ' . $funcionario->getEmpresa() . ' e ganha ' . $funcionario->getSalario();

Note: note that I used self::setNome in the Class Funcionario , however, it would also work as $this->setNome since we are talking about a inheritance, however, I prefer to use self as this makes it clear that the method was inherited and assigns semantics to the code.

You can still set the strick_types=1 and then work with input and output 'manual typing' (return). Here's a simple example:

<?php
declare(strict_types=1);

class Pessoa{     

    private $nome;
    private $idade;
    private $sexo;  

    protected function setNome(string $nome) : bool
    {
        if(!is_null($nome)) {
            $this->nome = $nome;
            return true;
        }

        return false;
    }

    protected function setIdade(int $idade) : bool
    {
        if(!is_null($idade)) {
            $this->idade = $idade;
            return true;
        }

        return false;
    }
    //...
 0
Author: Fábio Jânio, 2017-10-19 11:34:03