Объекты и классы в PHP. Основы синтаксиса

Краткое содержание лекции

Теоретические задания | Практические задания

Именем класса может быть любое слово, которое не входит в список зарезервированных слов PHP, начинающееся с буквы или символа подчеркивания и за которым следует любое количество букв, цифр или символов подчеркивания.

<?php
class Publication
{

}

//bad practice
$publication = new Publication;
//best practice
$publication = new Publication();
?>

В контексте класса можно создать новый объект через new self и new parent.

<?php
class Publication
{
    static public function getInstance()
    {
        return new self();
        //return new static();
        //return new parent();
    }
}
?>
<?php
class Publication
{
    //bad practice
    var $title = 'Title';
    //best practice
    public $text = 'Text of the publication';
}
?>
<?php
$publication = new Publication();
echo $publication->title . \PHP_EOL;
echo $publication->text . \PHP_EOL;
?>
<?php
class Publication
{
    public $title = 'Title';
    protected $text = 'Text of the publication';
    private $views = 0;
}
?>
<?php
$publication = new Publication();
echo $publication->title . \PHP_EOL;
// FATAL ERROR
echo $publication->text . \PHP_EOL;
// FATAL ERROR
echo $publication->views . \PHP_EOL;
?>
<?php
class Publication
{
    public $title = 'Title';
    protected $text = 'Text of the publication';
    private $_views = 0;

    //bad practice
    function getTitle()
    {
        return $this->title;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }

    public function getText()
    {
        return $this->text;
    }

    public function setText($text)
    {
        $this->text = $text;
    }

    public function getViews()
    {
        return $this->_views;
    }

    public function setViews($views)
    {
        $this->_views = $views;
    }
}
?>
<?php
$publication = new Publication();
echo $publication->getTitle() . \PHP_EOL;
echo $publication->getText() . \PHP_EOL;
echo $publication->getViews() . \PHP_EOL;
?>

Что необходимо изменить в классе Publication?

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class Publication
{
    /**
     * @var string
     */
    private $title = 'Title';

    /**
     * @var string
     */
    private $text = 'Text of the publication';

    /**
     * @var integer
     */
    private $views = 0;

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->text;
    }

    /**
     * @param string $text
     */
    public function setText($text)
    {
        $this->text = $text;
    }

    /**
     * @return integer
     */
    public function getViews()
    {
        return $this->views;
    }

    /**
     * @param integer $views
     */
    public function setViews($views)
    {
        $this->views = $views;
    }
}
?>

Как правильно добавить константу? Чем следующий пример плох?

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class Publication
{
    /**
     * @var string
     */
    private $title = 'Title';

    /**
     * @var string
     */
    private $text = 'Text of the publication';

    /**
     * @var integer
     */
    private $views = 0;

    //bad practice
    const author = 'fightmaster';

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->text;
    }

    /**
     * @param string $text
     */
    public function setText($text)
    {
        $this->text = $text;
    }

    /**
     * @return integer
     */
    public function getViews()
    {
        return $this->views;
    }

    /**
     * @param integer $views
     */
    public function setViews($views)
    {
        $this->views = $views;
    }
}
?>
<?php
echo Publication::author . \PHP_EOL;
echo $publication::author . \PHP_EOL;
// FATAL ERROR
echo $publication->author . \PHP_EOL;
?>

Добавим конструктор с "тупым" комментарием

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class Publication
{
    const AUTHOR = 'fightmaster';

    /**
     * @var string
     */
    private $title = 'Title';

    /**
     * @var string
     */
    private $text = 'Text of the publication';

    /**
     * @var integer
     */
    private $views = 0;

    /**
     * @var \DateTime
     */
    private $creationDate;

    /**
     * Constructor
     *
     * @todo remove stupid comment
     */
    public function __construct()
    {
        $this->creationDate = new \DateTime('now');
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->text;
    }

    /**
     * @param string $text
     */
    public function setText($text)
    {
        $this->text = $text;
    }

    /**
     * @return integer
     */
    public function getViews()
    {
        return $this->views;
    }

    /**
     * @param integer $views
     */
    public function setViews($views)
    {
        $this->views = $views;
    }
}
?>

Изменение технического задания

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class News extends Publication
{
    /**
     * @var string
     */
    private $author;

    //такая запись конструктора в дочернем объекте эквивалентна ее отсутствию
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        return $this->author;
    }

    /**
     * @param string $author
     */
    public function setAuthor($author)
    {
        $this->author = $author;
    }
}
?>
<?php
$news = new News();
$news->setAuthor('admin');
echo $news->getAuthor() . \PHP_EOL;
?>

А что нужно изменить в объекте Publication?

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class Publication
{
    const AUTHOR = 'fightmaster';

    /**
     * @var string
     */
    private $title = 'Title';

    /**
     * @var string
     */
    private $text = 'Text of the publication';

    /**
     * @var integer
     */
    private $views = 0;

    /**
     * @var \DateTime
     */
    private $creationDate;

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->text;
    }

    /**
     * @param string $text
     */
    public function setText($text)
    {
        $this->text = $text;
    }

    /**
     * @return integer
     */
    public function getViews()
    {
        return $this->views;
    }

    /**
     * @param integer $views
     */
    public function setViews($views)
    {
        $this->views = $views;
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        //return static::AUTHOR;
        return self::AUTHOR;
    }

    /**
     * @param string $author
     */
    public function setAuthor($author)
    {
    }
}
?>
<?php
$publication = new Publication();
$publication->setAuthor('admin');
echo $publication->getAuthor() . \PHP_EOL;
?>

Изменение технического задания

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class Publication
{
    const AUTHOR = 'fightmaster';

    /**
     * @var string
     */
    private $title = 'Title';

    /**
     * @var string
     */
    private $text = 'Text of the publication';

    /**
     * @var integer
     */
    private $views = 0;

    /**
     * @var \DateTime
     */
    private $creationDate;

    /**
     * @var string
     */
    private $slug;

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
        $this->generateSlug();
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->text;
    }

    /**
     * @param string $text
     */
    public function setText($text)
    {
        $this->text = $text;
    }

    /**
     * @return integer
     */
    public function getViews()
    {
        return $this->views;
    }

    /**
     * @param integer $views
     */
    public function setViews($views)
    {
        $this->views = $views;
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        //return static::AUTHOR;
        return self::AUTHOR;
    }

    /**
     * @param string $author
     * @throws \Exception
     */
    public function setAuthor($author)
    {
        throw \Exception(
            sprintf('Unable sets author to the publication "%s".', $this->getTitle())
        );
    }

    /**
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * Generates slug based on Title
     */
    private function generateSlug()
    {
        $this->slug = strtolower(str_replace(' ', '-', $this->getTitle()));
    }
}
?>
<?php
$publication = new Publication();
$publication->setTitle('Test slug');
echo $publication->getSlug() . \PHP_EOL;
?>

Создадим интерфейс SignedInterface

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
interface SignedInterface
{
    /**
     * @return string
     */
    function getAuthor();

    /**
     * @param string $author
     */
    function setAuthor($author);
}
?>

Кто его будет имплементировать?

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class Publication implements SignedInterface
{
    const AUTHOR = 'fightmaster';

    /**
     * @var string
     */
    private $title = 'Title';

    /**
     * @var string
     */
    private $text = 'Text of the publication';

    /**
     * @var integer
     */
    private $views = 0;

    /**
     * @var \DateTime
     */
    private $creationDate;

    /**
     * @var string
     */
    private $slug;

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
        $this->generateSlug();
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->text;
    }

    /**
     * @param string $text
     */
    public function setText($text)
    {
        $this->text = $text;
    }

    /**
     * @return integer
     */
    public function getViews()
    {
        return $this->views;
    }

    /**
     * @param integer $views
     */
    public function setViews($views)
    {
        $this->views = $views;
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        //return static::AUTHOR;
        return self::AUTHOR;
    }

    /**
     * @param string $author
     * @throws \Exception
     */
    public function setAuthor($author)
    {
        throw \Exception(
            sprintf('Unable sets author to the publication "%s".', $this->getTitle())
        );
    }

    /**
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * Generates slug based on Title
     */
    private function generateSlug()
    {
        $this->slug = strtolower(str_replace(' ', '-', $this->getTitle()));
    }
}
?>
<?php
$publication = new Publication();
$news = new News();
if ($publication instanceof SignedInterface && $news instanceof SignedInterface) {
    echo 'Классы реализовывают SignedInterface' . PHP_EOL;
}
?>

Изменение технического задания

Класс может быть объявлен, как абстрактный и не содержать абстрактных методов

Если класс имеет абстрактные методы, он обязан быть объялен как абстрактный

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
abstract class Publication implements SignedInterface
{
    const AUTHOR = 'fightmaster';

    /**
     * @var string
     */
    private $title = 'Title';

    /**
     * @var string
     */
    private $text = 'Text of the publication';

    /**
     * @var integer
     */
    private $views = 0;

    /**
     * @var \DateTime
     */
    private $creationDate;

    /**
     * @var string
     */
    private $slug;

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
        $this->generateSlug();
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->text;
    }

    /**
     * @param string $text
     */
    public function setText($text)
    {
        $this->text = $text;
    }

    /**
     * @return integer
     */
    public function getViews()
    {
        return $this->views;
    }

    /**
     * @param integer $views
     */
    public function setViews($views)
    {
        $this->views = $views;
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        //return static::AUTHOR;
        return self::AUTHOR;
    }

    /**
     * @param string $author
     * @throws \Exception
     */
    public function setAuthor($author)
    {
        throw \Exception(
            sprintf('Unable sets author to the publication "%s".', $this->getTitle())
        );
    }

    /**
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * Generates slug based on Title
     */
    private function generateSlug()
    {
        $this->slug = strtolower(str_replace(' ', '-', $this->getTitle()));
    }
}
?>

Добавим абстрактный метод getType()

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
abstract class Publication implements SignedInterface
{
    const AUTHOR = 'fightmaster';

    /**
     * @var string
     */
    private $title = 'Title';

    /**
     * @var string
     */
    private $text = 'Text of the publication';

    /**
     * @var integer
     */
    private $views = 0;

    /**
     * @var \DateTime
     */
    private $creationDate;

    /**
     * @var string
     */
    private $slug;

    /**
     * @return string
     */
    abstract public function getType();
    //abstract protected function getType();

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
        $this->generateSlug();
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->text;
    }

    /**
     * @param string $text
     */
    public function setText($text)
    {
        $this->text = $text;
    }

    /**
     * @return integer
     */
    public function getViews()
    {
        return $this->views;
    }

    /**
     * @param integer $views
     */
    public function setViews($views)
    {
        $this->views = $views;
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        //return static::AUTHOR;
        return self::AUTHOR;
    }

    /**
     * @param string $author
     * @throws \Exception
     */
    public function setAuthor($author)
    {
        throw \Exception(
            sprintf('Unable sets author to the publication "%s".', $this->getTitle())
        );
    }

    /**
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * Generates slug based on Title
     */
    private function generateSlug()
    {
        $this->slug = strtolower(str_replace(' ', '-', $this->getTitle()));
    }
}
?>
<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class Article extends Publication
{
    /**
     * @return string
     */
    public function getType()
    {
        return 'article';
    }
}
?>
<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class News extends Publication
{
    /**
     * @var string
     */
    private $author;

    /**
     * @return string
     */
    public function getType()
    {
        return 'news';
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        return $this->author;
    }

    /**
     * @param string $author
     */
    public function setAuthor($author)
    {
        $this->author = $author;
    }
}
?>
<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class Comment implements SignedInterface
{
    /**
     * @var string
     */
    private $author;

    /**
     * @var string
     */
    private $message;

    /**
     * @return string
     */
    public function getAuthor()
    {
        return $this->author;
    }

    /**
     * @param string $author
     */
    public function setAuthor($author)
    {
        $this->author = $author;
    }

    /**
     * @return string
     */
    public function getMessage()
    {
        return $this->message;
    }

    /**
     * @param string $message
     */
    public function setMessage($message)
    {
        $this->message = $message;
    }
}
?>
<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
interface Commentable
{
    /**
     * @return Comment[]
     */
    function getComments();

    /**
     * @param Comment $comment
     */
    function addComment(Comment $comment);
}
?>
<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
class News extends Publication implements Commentable
{
    /**
     * @var string
     */
    private $author;

    /**
     * Comment[]
     */
    private $comments = array();

    /**
     * @return string
     */
    public function getType()
    {
        return 'news';
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        return $this->author;
    }

    /**
     * @param string $author
     */
    public function setAuthor($author)
    {
        $this->author = $author;
    }

    /**
     * @return Comment[]
     */
    function getComments()
    {
        return $this->comments;
    }

    /**
     * @param Comment $comment
     */
    function addComment(Comment $comment)
    {
        $this->comments[] = $comment;
    }
}
?>
<?php
$comment = new Comment();
$news = new News();
$news->addComment($comment);
var_dump($news->getComments());
?>

Добавим возможность хранить общее количество просмотров для всех статей и новостей.

<?php
/**
 * @author Dmitry Petrov <dmitry.petrov@opensoftdev.ru>
 */
abstract class Publication implements SignedInterface
{
    const AUTHOR = 'fightmaster';

    private static $allViews = 0;

    /**
     * @var string
     */
    private $title = 'Title';

    /**
     * @var string
     */
    private $text = 'Text of the publication';

    /**
     * @var integer
     */
    private $views = 0;

    /**
     * @var \DateTime
     */
    private $creationDate;

    /**
     * @var string
     */
    private $slug;

    /**
     * @return string
     */
    abstract public function getType();
    //abstract protected function getType();

    public function view()
    {
        $this->views++;
        self::$allViews++;
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
        $this->generateSlug();
    }

    /**
     * @return string
     */
    public function getText()
    {
        return $this->text;
    }

    /**
     * @param string $text
     */
    public function setText($text)
    {
        $this->text = $text;
    }

    /**
     * @return integer
     */
    public function getViews()
    {
        return $this->views;
    }

    /**
     * @return integer
     */
    public function getAllViews()
    {
        return self::$allViews;
    }

    /**
     * @return string
     */
    public function getAuthor()
    {
        //return static::AUTHOR;
        return self::AUTHOR;
    }

    /**
     * @param string $author
     * @throws \Exception
     */
    public function setAuthor($author)
    {
        throw \Exception(
            sprintf('Unable sets author to the publication "%s".', $this->getTitle())
        );
    }

    /**
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * Generates slug based on Title
     */
    private function generateSlug()
    {
        $this->slug = strtolower(str_replace(' ', '-', $this->getTitle()));
    }
}
?>
<?php
$article = new Article();
$comment = new Comment();
$news = new News();
$news->addComment($comment);
$news->view();
$news->view();
$article->view();

echo $news->getType() . ' views ' . $news->getViews() . PHP_EOL;
echo $article->getType() . ' views ' . $article->getViews() . PHP_EOL;
echo 'All views from ' . $news->getType() . ' ' . $news->getAllViews() . PHP_EOL;
echo 'All views from ' . $article->getType() . ' ' . $article->getAllViews() . PHP_EOL;
?>

*Что будет, если заменить self на static У аттрибута allViews? *

Ключевое слово final

<?php
final class News
{

}

//fatal error
class BBCNews extends News
{

}
?>

Резервирование метода php <?php abstract class Publication { /** * Generates slug based on Title */ final private function generateSlug() { //code } } ?>

Namespace

<?php
namespace BBC;

class News
{

}
?>
<?php
namespace Lenta;

class News
{
    function strlen($string)
    {
        return \strlen($string);
    }
}
?>
<?php
use BBC\News;
use Lenta\News as LentaNews;

$news = new News();
$news = new BBC\News();
$news = new \BBC\News();

$news = new LentaNews();
$news = new BC\News()
?>