Error PHP POO Polymorphism

3

When developing a simple PHP POO application, I came across an unexpected error, and I have no idea why. I'm now starting to study object-oriented programming and I only have a small base in C #.

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

My goal is to simply create an object and pass all information to the method lerDados() of class Funcionario , and within it, call method LerDados() of class Pessoa ( parent::lerDados() ) ( nome , idade and sexo ), the others are "read" in the class itself Funcionario ( empresa and salario ).

  

Error: Declaration of Official :: readData ($ stringName, $ stringId, $ stringSex, $ stringCompany, $ stringSalary) should be compatible with Person :: stringName, $ stringSex) 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");
   ?>

Is it me that I am seriously wrong, or does PHP not accept this type of polymorphism? Could anyone guide me how to fix this, and answer why this brutally fatal error happened?

    
asked by anonymous 19.10.2017 / 06:27

2 answers

3

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

I see some problems in this code. First, I do not think there is an inheritance there. Some people disagree, but I think being an employee is just a role the person can have and there is no relationship is one .

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

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

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

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

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

Polymorphism occurs with same-signature methods . So the method of one class is not polymorphic in relation to the other. PHP does not have methods overload and therefore it prevents that there are two methods with same name and different signature. If the signature were the same there would be polymorphic and the child class would have only one method with the same name.

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

Constructors are not polymorphic, actually static. This 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 running on ideone . And no Coding Ground . Also I placed GitHub for future reference .

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

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

When you conceptualize wrong, OOP does not save anyone.

When doing OOP just because everyone is doing it, just the way a person said it is right and the mass gets copied without understanding why it is doing it is not appropriate.

    
19.10.2017 / 09:49
0

The way 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 can not simply be a Person (direct instance of the class), so the constructor of the Person class was set to protected , that is, it should be called by another class that inherits from Person.

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

See the 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. I personally like to use the famous setAtribute to set the value of my variables, but for what reason do I do this? Simple, to include validation in the assignment of values. The example below is very simple and does not reflect an actual stream of data validation, but it does serve to convey 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: I noticed that I used self::setNome in the Official class, but it would also work as $this->setNome since we're talking about an inheritance, however, I'd rather use self > as this makes it clear that the method has been inherited and assigns semantics to the code.

You can also set the strick_types=1 and then work with manual typing of input and output (return). Here is 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;
    }
    //...
    
19.10.2017 / 13:34