1

I am currently learning OOP concepts. I have used CodeIgniter, I know it has OOP concepts but I don't understand how it works. I just use the methods in the documentation.

I am now on the inheritance part.

Here is my code:

<?php

class Artist {
    public $name;
    public $genre;
    public $test = 'This is a test string';

    public function __construct(string $name, string $genre) {
        $this->name = $name;
        $this->genre = $genre;
    }
}

class Song extends Artist {
    public $title;
    public $album;

    public function __construct(string $title, string $album) {
        $this->title = $title;
        $this->album = $album;
    }

    public function getSongArtist() {
        return $this->name;
    }
}

$artist = new Artist('Joji Miller', 'Lo-Fi');
$song = new Song('Demons', 'In Tounges');

echo $song->getSongArtist(); // returns nothing

From what I understand inheritance will let me access properties and methods from the parent class.

In my example I have instantiate the Artist. So now I have Joji Miller as artist name.

Now, if I instantiate the Song class, I thought that I can access the artist name since I am extending the Artist class. But it is just empty.

Would you help me understand why it is not getting the artist name?

Hope I explained myself clearly. Thankyou..

9
  • you do not need to instantiate the parent class. Just call the child class as it already extends the parent. Commented Feb 9, 2018 at 15:12
  • 3
    Song extends Artist ? Sounds weird ;-) Commented Feb 9, 2018 at 15:14
  • 1
    Is a Song an Artist? Could you substitute a Song any place you'd use an Artist? … Then those two things have nothing in common and should not inherit each other. Commented Feb 9, 2018 at 15:16
  • 3
    Indeed. Hint: not here. Practically speaking, you don't need inheritance all that often. Start simple without it. Add it later when you experience bottlenecks with code reuse; which is what inheritance is mostly about. Here you simply want three independent classes: Song, Artist and Album, and you pass them to each other in some order that makes sense. E.g.: $ar = new Artist('Foo'); $al = new Album('Bar', $ar); $al->addSong(new Song('Baz', $ar)); Commented Feb 9, 2018 at 15:21
  • 1
    That is what OOP is all about: passing objects around instead of simple primitive values. Commented Feb 9, 2018 at 15:31

3 Answers 3

9

Heh. Learning "oop principles" from CodeIgniter is like going to North Korea to study democracy. And you have already learned the wrong things.

The extends keyword should be read as "is special case of". As in class Admin extends User means that the admin instance is a more specialized case of generic user.

And that's where you are wrong. Song is not a subtype of an artist.

Instead the song has an artist, which performs it. As in:

$artist = new Artist('Freddie Mercury');
$song = new Song('Another One Bites the Dust', $artist);

echo $song->getArtist()->getName();

Another bad practice, that you seem to have picked up: stop defining class variables as public. That breaks the encapsulation. Instead those values should be assigned using methods, because then you will e able top track, format and validate those values.

Sign up to request clarification or add additional context in comments.

2 Comments

North Korea - 😆😀👍
Hehe. You are funny. Thankyou. I also have read about the visibility. Still learning when to use protected and private. I appreciate the tips.
5

First of all in your case you have not the best example of inheritance... And it leads to confusion...

I'd rather advise you to have in base class base behavior related to all descendants, like here.
Base class:

<?php

class SomethingWithName
{
    private $name;
    public function __construct(string $name)
    {
        $this->name = $name;
    }
    public function getName(): string
    {
        return $this->name;
    }
}

Your classes:

class Artist extends SomethingWithName
{
    private $genre;
    public function __construct(string $name, string $genre)
    {
        parent::__construct($name);
        $this->genre = $genre;
    }
    public function getGenre(): string
    {
        return $this->genre;
    }
}

class Song extends SomethingWithName
{
    private $album;
    private $artist;
    public function __construct(string $name, string $album, Artist $artist)
    {
        parent::__construct($name);
        $this->album = $album;
        $this->artist = $artist;
    }
    public function getAlbum(): string
    {
        return $this->album;
    }
    public function getArtist(): Artist
    {
        return $this->artist;
    }
}

Result:

$a = new Artist('Joji Miller', 'Lo-Fi');
$s = new Song('Demons', 'In Tounges', $a);
var_export([
    $s->getName(), // Demons
    $s->getAlbum(), // In Tounges
    $s->getArtist()->getName(), // Joji Miller
    $s->getArtist()->getGenre(), // Lo-Fi
]);

4 Comments

Hi Vladimir, thanks for the detailed answer. One question, is my understanding right that we need to use parent::__construct() if we have to call a property from a parent class? I have seen parent::__construct in CodeIgniter.
The HasName should be an interface and not a superclass.
@danangeloalcanar When your parent __construct method contains some stuff which you need to use in your child class (init some properties, etc) - then you have to call parent::__construct() in 9 out of 10 cases, but it always depends on particular implementation...
@tereško Yes, it sounds really reasonable to have interface HasName, but I didn't manage to find something else common between Artist and Song as base class, that's why decided to use this one to show concept of simple inheritance...
1

That's because when defining the Song class's __construct() function you are overriding the Artist's __contruct() function. Which is the function that gets called when you do $song = new Song(...)

Using the keyword parent:: you can access the parent's classes functions.

The following works.

<?php

class Artist {
    public $name;
    public $genre;
    public $test = 'This is a test string';

    public function __construct(string $name, string $genre) {
        $this->name = $name;
        $this->genre = $genre;

    }

}

class Song extends Artist {
    public $title;
    public $album;

    public function __construct(string $title, string $album, string $ArtistName, string $genre) {
        $this->title = $title;
        $this->album = $album;

        parent::__construct($ArtistName, $genre);
    }

    public function getSongArtist() {
        return $this->name;
    }
}

$artist = new Artist('Joji Miller', 'Lo-Fi');
$song = new Song('Demons', 'In Tounges','Joji Miller', 'Lo-Fi');

echo $song->getSongArtist(); // returns nothing

2 Comments

Oh I see. You can call the construct function of the artist class inside the song class. That is the use of parent:: Thanks Fredster. I learned new things..
No problem. Exactly, that's how to use parent::. You can accept my answer as correct then! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.