What is the best way to create your own class in PHP?

I know with a bat, some of you assume an interface or an abstract, but that only handles SOME situations. Here is an example where they break.

Suppose we have classes that implement the same interface and extend the same base

  class car extends fourwheeler implements ipaygas{       

    protected $tank1;

    //interface
    public function payGas($amount){}

  }

  class sportscar extends fourwheeler implements ipaygas{

    protected $tank1;
    protected $tank2;

    //interface
    public function payGas($amount){}

  }

  interface ipaygas{

    function payGas($amount);
  }

In some situations, an interface is all you need as you can only execute "payGas ()". But what do you do when you have the conditions for satisfaction.

Example: if, before paying gas, you need to (1) check the type of car, (2) use premium gas for the sports car, and (3) fill the second tank of the sports car.

THIS IS WHAT I WANT TO DO, BUT CANNOT

   function pumpAndPay(iPayGas $car){
     if(gettype($car) == "car"){
       fillTank($car,(car) $car->tank1);
     }else{
       fillTank($car,(sportscar) $car->tank1);
       fillTank($car,(sportscar) $car->tank2);
     }
   }

How can I do this with real type castings? Is this possible in PHP?

( ): "" ... , , , , , , , ..

   abstract class AVechicle{}
   abstract class ACar extends AVechicle{}
   abstract class ATruckOrSUV extends AVechicle{}
   abstract class ABike extends AVechicle{}

   class Car extends ACar{}
   class SportsCar extends ACar{}
   class SUV extends ATruckOrSUV{}
   class Truck extends ATruckOrSUV{}
   class Bike extends ABike{}
   class Scooter extends ABike{}

   class GasStation{

     public function cleanVehicle(AVehicle $car){
       //assume we need to check the car type to know
       //what type of cleaner to use and how to clean the car
       //if the car has leather or bucket seats

       //imagine we have to add an extra $2/h for sports cars

       //imagine a truck needs special treatment tires
       //or needs inspection
     }

     public function pumpAndPay(AVehicle $car){
       //need to know vehicle type to get gas type

       //maybe we have a special for scooters only, Green Air campaign etc.
     }

     public function fullService(AVehicle $car){
       //need to know if its a truck to do inspection FIRST

       $this->cleanVehicle($car);
       $this->pumpAndPay($car);

       //bikes get 10% off
       //cars get free carwash
     }

   }

...

+3
5

, .

, . fillTank , , , , , . - :

abstract class Vehicle
{
    protected $tank1;
    protected $tank2;

    // Declaring an abstract function in parent class forces all child class to 
    // implement same class
    abstract public function fillGas() {}
}

class Car extends Vehicle
{
    public function fillGas()
    {
        $this->tank1 = 'full';
    }
}

class SportsCar extends Vehicle
{
    public function fillGas()
    {
        $this->tank1 = 'full';
        $this->tank2 = 'full';
    }
}

class Skateboard extends Vehicle
{
    // Skateboards don't have gastanks, just here to sastify parent abstract definition
    public function fillGas() {}
}

, OP , , , . .

- traits ( PHP 5.4). -, , , .

- -

( ): "" ... , , , , , gas_type, cleaner_type, ..

, , - Vehicle, , , .., , GasStation::cleanVehicle() factory .

, , , GasStation . 5 , , factory .. :

abstract class Vehicle
{
    // Setting these to public for demonstration only, otherwise you should set these 
    //  to protected and write public accessors 
    public $paintType;
    public $bodyType;
    public $interior;
}

class Car extends Vehicle
{
}

class Suv extends Vehicle
{
}

class Truck extends Vehicle
{
}

class GasStation
{
    public static function cleanVehicle(Vehicle $vehicle)
    {
        switch (get_class($vehicle)) {

            case 'Car':
                // Car specific cleaning
                break;

            case 'Truck':
                // Truck specific cleaning
                break;

            default:
                throw new Exception(sprintf('Invalid $vehicle: %s', serialize($vehicle)));
        }

        // We've gone through our vehicle specific cleaning, now we can do generic
        if ('Leather' === $vehicle->getInterior()) {
            // Leather specific cleaning
        }

        if ('Sedan' === $vehicle->getBodyType()) {
            // Sedan specific cleaning
        }
    }
 }

$car = new Car();

$car->setPaintType = 'Glossy';
$car->setBodyType = 'Sedan';
$car->setInterior = 'Cloth';

$suv = new Suv();

$suv->setPaintType = 'Glossy';
$suv->setBodyType = 'Crossover';
$suv->setInterior = 'Leather';

$truck = new Truck();

$truck->setPaintType = 'Flat';
$truck->setBodyType = 'ClubCab';
$truck->setInterior = 'Cloth';

$vehicles = array($car, $suv, $truck);

foreach ($vehicles as $vehicle) {
    GasStation::cleanVehicle($vehicle);
}
+3

, .

, . , /? , . ,

class FillingStation
{
   protected $vehicles = array();

   public function addVehicle(Vehicle $vehicle) {
      $this->vehicles[] = $vehicle;
   }

   public function fillTanks() {
     foreach($this->vehicles as $vehicle) {
        $vehicle->fillTank();
     }
   }
}

,

abstract class Vehicle
{
  public $fillLevel = 0;

  abstract public function fillTank();
}

class Car extends Vehicle
{
  public function fillTank()
  {
     // ... do some stuff here, e.g.:
     $this->fillLevel = 100;
  }
}

class SportsCar extends Vehicle
{
  // ....

:

$parkingLot = new FillingStation();
$parkingLot->addVehicle(new Car());
$parkingLot->addVehicle(new SportsCar());

$parkingLot->fillTanks();

, , , , , , , .

+2

instanceof is_a, .

pumpAndPay , , . , ( , ). , , :

interface IPaygas
{
    private tank1;
    public function payGas($amount);
}

interface IPaygasMultiTank extends IPaygas
{
    private tank2;
}
+1
source

Your mistake here:

fillTank($car,(sportscar) $car->tank1);

Almost all of your class properties must be protected or private. In principle, one class should not perform operations on other properties of the class. Instead, the car should work with its internal elements, and PumpAndPay only works with the fillTank method.

   function pumpAndPay(iPayGas $car){
       $amount = $car->fillTank();
       $car->payGas($amount);
   }

   interface ipaygas{

       function payGas($amount);
       function fillTank($amount);
   }
0
source

All you have to do is do the following:

if($val instanceof whatever.class){
  $val->dostuff();
}
0
source

All Articles