Chapterبەش 6 · Lectureوانە 6.1

Classes and Objects in PHPکلاسەکان و ئۆبجێکتەکان لە PHPـدا

Why object-oriented PHP, and how to write it: classes, properties and methods, new, the arrow -> (the same arrow as $conn->query() in the MySQL lessons), $this, constructors and PHP 8 constructor property promotion, typed properties, public, private and protected, readonly (PHP 8.1), static members and ::, class constants, a bazaar Product and Cart worked example, objects as shared handles and clone, and common mistakes with PHP's real messages. Every example runs on PHP 8.2 and works the same on 8.3, 8.4 and 8.5.

بۆچی PHPـی تەنخواز و چۆن دەنووسرێت: ، و ، new، تیری -> (هەمان تیری ⁦$conn->query()⁩ لە وانەکانی MySQL)، ⁦$this⁩، و ⁦PHP 8⁩، جۆردار، public، private و protected، ⁦readonly (PHP 8.1)⁩، و ::، ، نموونەیەکی کارپێکراوی Product و Cartـی بازاڕ، وەک دەسکی هاوبەش و clone و هەڵە باوەکان بە پەیامە ڕاستەقینەکانی PHP. هەموو نموونەیەک لەسەر ⁦PHP 8.2⁩ کار دەکات و لەسەر ⁦8.3⁩، ⁦8.4⁩ و ⁦8.5⁩ هەمان شتە.

23 min read22 خولەک خوێندنەوە · 20 stepsهەنگاو

What you will learnچی فێر دەبیت

  • Write a class with typed properties and methods, and make objects from it with new.
  • Use -> and $this correctly, and explain the arrow you already used with $conn->query().
  • Write a constructor, in the long form and with PHP 8 promotion.
  • Choose public, private or readonly, and use static members and class constants with ::.
  • Read PHP's error messages about classes and objects and fix the code.
  • بە جۆردار و بنووسیت و بە new لێ دروست بکەیت.
  • -> و ⁦$this⁩ بە دروستی بەکار بهێنیت و ئەو تیرە ڕوون بکەیتەوە کە پێشتر لەگەڵ ⁦$conn->query()⁩ بەکارت هێنا.
  • بنووسیت، بە شێوە درێژەکە و بە ⁦PHP 8⁩.
  • public، private یان readonly هەڵبژێریت و و بە :: بەکار بهێنیت.
  • پەیامەکانی هەڵەی PHP لەبارەی و بخوێنیتەوە و کۆدەکە چاک بکەیت.

Why objects in PHP?بۆچی ئۆبجێکتەکان لە PHPـدا؟

Until now your data lived in variables and arrays, and functions worked on it from outside. This style is called , and it is fine for a small script. A real shop site is different: hundreds of products, carts and orders. Soon you have many arrays and many functions, and nothing says which function belongs to which array. A typing mistake in a key, such as $tea["prise"], only gives a warning when the page runs.

تا ئێستا تۆ لە و بوو و لە دەرەوە کاریان لەسەر دەکرد. ئەم شێوازە پێی دەڵێن و بۆ بچووک باشە. ماڵپەڕی دووکانێکی ڕاستەقینە جیاوازە: سەدان بەرهەم، سەبەتە و داواکاری. زوو دەبینیت و زۆرت هەیە و هیچ شتێک نالێت کام هی کام . هەڵەیەکی نووسین لە ، وەک $tea["prise"]، تەنیا لە کاتی کارکردنی لاپەڕەکەدا دەدات.

(OOP) puts the data and the functions that use it together in one unit: an . You have already used objects: in Connecting PHP to MySQL, $conn->query($sql) called a method of a mysqli object. In this lesson you write your own. The big ideas are the same in every language and are also taught in Python and Java; here we focus on how PHP writes them.

⁦(OOP)⁩ و ئەو بەکاری دەهێنن لە یەک یەکەدا کۆ دەکاتەوە: . پێشتر بەکار هێناوە: لە بەستنەوەی PHP بە MySQL، $conn->query($sql) mysqli بانگ کرد. لەم وانەیەدا خۆت دەنووسیت. بیرۆکە گەورەکان لە هەموو زمانێکدا وەک یەکن و لە Python و Javaـیشدا دەخوێندرێن؛ لێرەدا سەرنج دەدەینە سەر ئەوەی PHP چۆنیان دەنووسێت.

Left, in orange: an array $tea with the keys name and price, two separate functions label($p) and setPrice(&$p, $new), and the line echo $tea["prise"]; with a typo. Notes: nothing ties the data to its functions; a wrong key is found only when the page runs. Right, in green: one object $tea of class Product, with data (name = "Tea", price = 5000) and actions (label(), setPrice()) in one box. Notes: data and actions travel together; the class decides what every product has. Bottom: object-oriented programming keeps a thing's data and its actions in one place.لای چەپ، بە پرتەقاڵی: ڕیزەکی $tea بە کلیلەکانی name و price، دوو کرداری جیای label($p) و setPrice(&$p, $new) و دێڕی echo $tea["prise"]; کە هەڵەی نووسینی تێدایە. تێبینییەکان: هیچ شتێک دراوەکە بە کردارەکانەوە نابەستێتەوە؛ کلیلێکی هەڵە تەنیا لە کاتی کارکردندا دەردەکەوێت. لای ڕاست، بە سەوز: ئۆبجێکتێکی $tea لە کلاسی Product، بە دراوە (name = "Tea"، price = 5000) و کارەکان (label() و setPrice()) لە یەک سندووقدا. تێبینییەکان: دراوە و کارەکان پێکەوە دەڕۆن؛ کلاسەکە دیاری دەکات هەر بەرهەمێک چی هەبێت. خوارەوە: بەرنامەسازیی تەنخواز دراوەی شتێک و کارەکانی لە یەک شوێندا دادەنێت.
An array and loose functions, or one object. و پەرشوبڵاو، یان یەک .CêIT

Class: the plan; object: a thing made from itکلاس: نەخشەکە؛ ئۆبجێکت: شتێک کە لێی دروست دەکرێت

A is a plan. It lists the (the data) that each object will have and the (the functions) it can run. An is one thing built from that plan, with its own values. Making an object from a class is also called making an of it. One Product class can give you as many product objects as the shop needs: tea, rice, honey…

نەخشەیەکە. ئەو () ڕیز دەکات کە هەر دەیبێت و ئەو () کە دەتوانێت جێبەجێیان بکات. یەک شتە کە لەو نەخشەیە دروست کراوە و خۆی هەیە. دروستکردنی لە پێی دەگوترێت دروستکردنی ئەو . یەک Product دەتوانێت هەر چەند بەرهەمی پێویستی دووکانەکە بێت بدات: چا، برنج، هەنگوین…

The price-tag padدەفتەری کاغەزی نرخ

A bazaar shopkeeper buys a pad of printed price tags: Name: ____ Price: ____ IQD. The printed pad is the class: every tag has the same two blanks. Each filled tag stuck on a jar (Tea, 5,000) is an object: same shape, its own values.

دووکاندارێکی بازاڕ دەفتەرێک کاغەزی نرخی چاپکراو دەکڕێت: ناو: ⁦____⁩ نرخ: ⁦____⁩ دینار. دەفتەرە چاپکراوەکە : هەموو کاغەزێک هەمان دوو بۆشایی هەیە. هەر کاغەزێکی پڕکراوە کە بە قوتووێکەوە نووسێنراوە (چا، ⁦5,000⁩) : هەمان شێوە، بەڵام خۆی.

Where the analogy stops workingسنووری ئەم نموونەیە

A paper tag cannot do anything, but an object also has methods: it can, for example, print its own label.

کاغەزێک ناتوانێت هیچ کارێک بکات، بەڵام هەیە: بۆ نموونە دەتوانێت لەیبڵی خۆی چاپ بکات.

Left: the class Product, drawn as a box with the properties name: string and price: int above and the method label(): string below. Arrows marked new go to three objects on the right: $tea with name "Tea" and price 5000, $rice with name "Rice 5 kg" and price 12000, and $honey with name "Honey" and price 15000. Bottom: the same properties and methods, but different values.لای چەپ: کلاسی Product، وەک سندووقێک کە تایبەتمەندییەکانی name: string و price: int لە سەرەوە و میتۆدی label(): string لە خوارەوەیە. تیرەکانی new بۆ سێ ئۆبجێکت لای ڕاست دەچن: $tea بە name "Tea" و price 5000، $rice بە name "Rice 5 kg" و price 12000 و $honey بە name "Honey" و price 15000. خوارەوە: هەمان تایبەتمەندییەکان و میتۆدەکان، بەڵام نرخی جیاواز.
One class, many objects.یەک ، چەندین .CêIT

Writing a class and making an objectنووسینی کلاسێک و دروستکردنی ئۆبجێکتێک

Write class, a name and a pair of braces. Inside the braces go the properties (variables with a visibility word such as public, an optional type and a default value) and the methods (functions). The class alone does nothing: new makes an object from it.

class، ناوێک و جووتێک کەوانەی ⁦{ }⁩ بنووسە. لە ناو کەوانەکاندا دێن ( بە وەک public، جۆرێکی ئارەزوومەندانە و ) لەگەڵ (). خودی هیچ ناکات: new لێ دروست دەکات.

A first class: Productیەکەم کلاس: Productfirst_class.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public string $name = "";
    public int $price = 0;

    public function label(): string
    {
        return $this->name . ": " . number_format($this->price) . " IQD";
    }
}

$tea = new Product();      // make an object from the class
$tea->name = "Tea";        // set its properties
$tea->price = 5000;

echo $tea->label(), "\n";  // call a method
echo $tea->price, "\n";    // read a property
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 2

class and a name. Class names are written in PascalCase: every word starts with a capital letter (Product, ShoppingCart).

class و ناوێک. ناوی بە PascalCase دەنووسرێن: هەموو وشەیەک بە پیتی گەورە دەست پێ دەکات (Product، ShoppingCart).

Lineدێڕی 4-5

Two properties: a visibility word (public), a type (string, int), the name with $ and a default value.

دوو : (public)، جۆرێک (string، int)، ناوەکە بە $ و .

Lineدێڕی 7-10

A method is a function written inside the class. $this means "this object"; the next screen explains it.

کە لە ناو نووسراوە. $this واتە «ئەم »؛ شاشەی داهاتوو ڕوونی دەکاتەوە.

Lineدێڕی 13

new Product() makes an object; $tea holds it.

new Product() دروست دەکات؛ $tea هەڵیدەگرێت.

Lineدێڕی 14-15

The arrow -> reaches a property of the object to set it.

تیری -> دەگاتە بۆ ئەوەی بداتێ.

Lineدێڕی 17-18

With brackets ->label() calls a method; without them ->price reads a property.

بە کەوانەوە ->label() بانگ دەکات؛ بەبێ کەوانە ->price دەخوێنێتەوە.

The class Product as code, with four labels: class + a name in PascalCase; properties: visibility, type, name, default value; a method: a function inside the class; $this = the object the method works on. Bottom: every method and property sits inside the braces { } of the class.کلاسی Product وەک کۆد، بە چوار ڕوونکردنەوە: وشەی class و ناوێک بە PascalCase؛ تایبەتمەندییەکان: دیاریکەری دەستڕاگەیشتن، جۆر، ناو، نرخی بنەڕەتی؛ میتۆدێک: کردارێک لە ناو کلاسەکەدا؛ $this = ئەو ئۆبجێکتەی میتۆدەکە کاری لەسەر دەکات. خوارەوە: هەموو میتۆد و تایبەتمەندییەک لە ناو کەوانەکانی { }ـی کلاسەکەدان.
The parts of a class.بەشەکانی .CêIT

Writing a class and making an objectنووسینی کلاسێک و دروستکردنی ئۆبجێکتێک

The arrow ->: reaching inside an objectتیری ->: چوونە ناو ئۆبجێکتێک

-> is the . $tea->price reads a property (no brackets), and $tea->label() calls a method (with brackets). After the arrow the property name has no $. It is the same arrow you met in The object operator ->: $conn->query($sql) calls the query() method of a mysqli object, and $result->num_rows reads a property of a result object.

-> . $tea->price دەخوێنێتەوە (بێ کەوانە) و $tea->label() بانگ دەکات (بە کەوانەوە). لە دوای تیرەکە ناوی $ـی نییە. ئەمە هەمان تیرە کە لە کارپێکەری ئۆبجێکت ->دا بینیت: $conn->query($sql) query()ـی mysqli بانگ دەکات و $result->num_rows ئەنجام دەخوێنێتەوە.

Top: $tea->price split into three boxes: $tea (the object, a variable), -> (the object operator) and price (a property: no $, no brackets); beside it $tea->label() (a method: with brackets, it runs). Middle, in orange with a cross: $tea->$price, a $ after the arrow is a mistake, PHP looks for a variable $price, and the message Warning: Undefined variable $price. Bottom, with a tick: $tea->price, write the name after the arrow without $.سەرەوە: $tea->price بە سێ سندووق دابەش کراوە: $tea (ئۆبجێکتەکە، گۆڕاوێک)، -> (کارپێکەری ئۆبجێکت) و price (تایبەتمەندییەک: بێ $، بێ کەوانە)؛ لە تەنیشتیەوە $tea->label() (میتۆدێک: بە کەوانەوە، جێبەجێ دەبێت). ناوەڕاست، بە پرتەقاڵی و خاچێک: $tea->$price، $ لە دوای تیرەکە هەڵەیە، PHP بەدوای گۆڕاوی $price دەگەڕێت و پەیامی Warning: Undefined variable $price. خوارەوە، بە نیشانەی ڕاست: $tea->price، ناوەکە لە دوای تیرەکە بێ $ بنووسە.
Object, arrow, member name: no $ after the arrow.، تیر، ناوی بەشەکە: لە دوای تیرەکە $ نییە.CêIT

A $ after the arrow is a common slip. PHP then takes the value of the variable $price as the property name (an advanced feature called variable property names). Here $price does not exist, so you get two warnings and no price:

$ لە دوای تیرەکە هەڵەیەکی باوە. ئەوکات PHP $price وەک ناوی بەکار دەهێنێت (توانایەکی پێشکەوتووی PHPـە: ناوی لە ). لێرەدا $price بوونی نییە، بۆیە دوو وەردەگریت و هیچ نرخێک چاپ ناکرێت:

A $ after the arrow$ لە دوای تیرەکەarrow_dollar.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public string $name = "Tea";
    public int $price = 5000;
}

$tea = new Product();
echo $tea->$price, "\n";   // wrong: a $ after the arrow

$this: the object the method works on⁦$this⁩: ئەو ئۆبجێکتەی میتۆدەکە کاری لەسەر دەکات

A method is written once, in the class, but it runs for many objects. Inside the method, $this is the object the method was called on: in $tea->label() it is $tea, and in $honey->label() it is $honey. So $this->name means "the name of this object". Python writes self for the same idea (Python classes), and Java writes this.

تەنیا یەک جار لە دەنووسرێت، بەڵام بۆ چەندین جێبەجێ دەبێت. لە ناو ، $this ئەو کە لەسەر بانگ کراوە: لە $tea->label()ـدا $teaـیە و لە $honey->label()ـدا $honeyـیە. بۆیە $this->name واتە «ناوی ئەم ». Python بۆ هەمان بیرۆکە self دەنووسێت (کلاسەکانی Python) و Java this دەنووسێت.

One method, two objectsیەک میتۆد، دوو ئۆبجێکتtwo_objects.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public string $name = "";
    public int $price = 0;

    public function label(): string
    {
        return $this->name . ": " . number_format($this->price) . " IQD";
    }
}

$tea = new Product();
$tea->name = "Tea";
$tea->price = 5000;

$honey = new Product();
$honey->name = "Honey";
$honey->price = 15000;

echo $tea->label(), "\n";    // inside label(), $this is $tea
echo $honey->label(), "\n";  // inside label(), $this is $honey
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 9

$this is whichever object stands before the arrow in the call.

$this هەر ئەو کە لە بانگکردنەکەدا پێش تیرەکە هاتووە.

Lineدێڕی 21-22

The same label() gives two different results.

هەمان label() دوو ئەنجامی جیاواز دەدات.

An animation in four steps. The method label() is shown with $this highlighted twice, beside two objects: $tea (name "Tea", price 5000) and $honey (name "Honey", price 15000). Step 1: label() is written once, in the class. Step 2: echo $tea->label(); an arrow goes from $this to $tea and the result is Tea: 5,000 IQD. Step 3: echo $honey->label(); the arrow goes to $honey and the result is Honey: 15,000 IQD. Step 4: $this = the object written before the arrow.
An animation in four steps. The method label() is shown with $this highlighted twice, beside two objects: $tea (name "Tea", price 5000) and $honey (name "Honey", price 15000). Step 1: label() is written once, in the class. Step 2: echo $tea->label(); an arrow goes from $this to $tea and the result is Tea: 5,000 IQD. Step 3: echo $honey->label(); the arrow goes to $honey and the result is Honey: 15,000 IQD. Step 4: $this = the object written before the arrow.
$this follows the object before the arrow.⁦$this⁩ شوێنی ئەو دەکەوێت کە پێش تیرەکەیە.CêIT

$this: the object the method works on⁦$this⁩: ئەو ئۆبجێکتەی میتۆدەکە کاری لەسەر دەکات

Common mistake: forgetting $this->هەڵەی باو: لەبیرکردنی ⁦$this->⁩

Inside a method, $name alone is a new of that method, not the property. PHP does not look inside the object by itself, so the method below prints two warnings and an empty label:

لە ناو ، $name بە تەنیا نوێی ئەو ، نەک . PHP خۆی ناچێتە ناو ، بۆیە ئەم خوارەوە دوو و لەیبڵێکی بەتاڵ چاپ دەکات:

$this-> is missing⁦$this->⁩ نییەforgot_this.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public string $name = "Tea";
    public int $price = 5000;

    public function label(): string
    {
        return $name . ": " . $price . " IQD";   // $this-> is missing
    }
}

$tea = new Product();
echo $tea->label(), "\n";

The fix is to say whose name you mean: return $this->name . ": " . $this->price . " IQD";.

چارەسەرەکە ئەوەیە بڵێیت ناوی کێت مەبەستە: return $this->name . ": " . $this->price . " IQD";.

Constructors: __construct()دروستکەرەکان: ⁦__construct()⁩

Setting every property by hand after new is slow and easy to forget. A is a method named __construct that PHP runs by itself each time new makes an object. The arguments you write in new Product("Tea", 5000) go to its parameters. Methods whose names start with two underscores are PHP's magic methods (): PHP calls them for you at the right moment.

دانانی هەموو بە دەست دوای new هێواشە و ئاسان لەبیر دەچێت. بە ناوی __construct کە PHP خۆی هەر جارێک new دروست بکات جێبەجێی دەکات. ئەو لە new Product("Tea", 5000)ـدا دەینووسیت دەچنە . ئەو ناویان بە دوو هێڵی ژێرەوە دەست پێ دەکات PHPـن: PHP خۆی لە کاتی گونجاودا بانگیان دەکات.

A constructor fills the propertiesدروستکەرێک تایبەتمەندییەکان پڕ دەکاتەوەconstructor.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public string $name;
    public int $price;

    public function __construct(string $name, int $price)
    {
        $this->name = $name;     // property = parameter
        $this->price = $price;
        echo "Made: $name\n";
    }

    public function label(): string
    {
        return $this->name . ": " . number_format($this->price) . " IQD";
    }
}

$tea = new Product("Tea", 5000);
$rice = new Product("Rice 5 kg", 12000);

echo $tea->label(), "\n";
echo $rice->label(), "\n";
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 4-5

Typed properties without a default value: the constructor gives them their values.

بە جۆر و بێ : پێ دەدات.

Lineدێڕی 7-12

$this->name is the property; $name is the parameter.

$this->name ؛ $name .

Lineدێڕی 20-21

Each new runs the constructor once: "Made: …" is printed twice.

هەر newـێک یەک جار جێبەجێ دەکات: «Made: …» دوو جار چاپ دەکرێت.

The line $tea = new Product("Tea", 5000); and four steps: 1. PHP makes an empty Product object; 2. PHP calls the constructor __construct("Tea", 5000); 3. the constructor fills the properties ($this->name = "Tea"); 4. the ready object goes into $tea. Bottom: the constructor runs by itself, once, every time you write new; its name, __construct, starts with two underscores.دێڕی $tea = new Product("Tea", 5000); و چوار هەنگاو: ١. PHP ئۆبجێکتێکی بەتاڵی Product دروست دەکات؛ ٢. PHP دروستکەرەکە __construct("Tea", 5000) بانگ دەکات؛ ٣. دروستکەرەکە تایبەتمەندییەکان پڕ دەکاتەوە ($this->name = "Tea")؛ ٤. ئۆبجێکتەکە ئامادەیە و دەچێتە ناو $tea. خوارەوە: دروستکەرەکە خۆی، یەک جار، هەر جارێک new بنووسیت جێبەجێ دەبێت؛ ناوەکەی، __construct، بە دوو هێڵی ژێرەوە دەست پێ دەکات.
What new does, step by step.new چی دەکات، هەنگاو بە هەنگاو.CêIT

Constructors: __construct()دروستکەرەکان: ⁦__construct()⁩

Constructor property promotion (PHP 8.0)بەرزکردنەوەی پارامیتەر بۆ تایبەتمەندی ⁦(PHP 8.0)⁩

In the last example every property is written three times: in the declaration, as a parameter and in an assignment. Since PHP 8.0 a constructor parameter that starts with a visibility word (public, protected or private, also readonly) is promoted: PHP declares the property and fills it with the argument. The body may stay empty, {}; code you write there runs after the properties are filled.

لە نموونەی پێشوودا هەموو سێ جار نووسراوە: لە ناساندندا، وەک و لە دانانی . لە ⁦PHP 8.0⁩ـەوە کە بە دەست پێ دەکات (public، protected یان private، هەروەها readonly) بەرز دەکرێتەوە: PHP دەناسێنێت و بە پڕی دەکاتەوە. جەستەکە دەتوانێت بەتاڵ بمێنێتەوە، {}؛ ئەو کۆدەی تێیدا دەینووسیت دوای پڕکردنەوەی جێبەجێ دەبێت.

The same Product with promotionهەمان Product بە بەرزکردنەوەی پارامیتەر بۆ تایبەتمەندیpromotion.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public function __construct(
        public string $name,
        public int $price,
    ) {}

    public function label(): string
    {
        return $this->name . ": " . number_format($this->price) . " IQD";
    }
}

$rice = new Product("Rice 5 kg", 12000);
echo $rice->label(), "\n";
echo $rice->name, "\n";
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 4-7

Each public parameter becomes a property. The comma after the last parameter is allowed (PHP 8.0).

هەر public دەبێتە . فاریزە لە دوای دوایین ڕێگەپێدراوە ⁦(PHP 8.0)⁩.

Lineدێڕی 15-16

The object works exactly like the long version.

ڕێک وەک وەشانە درێژەکە کار دەکات.

Left, the long form of class Product: two property declarations, a constructor with the parameters string $name and int $price, and two lines $this->name = $name; and $this->price = $price;. Right, the short form for PHP 8.0 and later: public function __construct(public string $name, public int $price) {}. An equals sign between them. Note: public before a parameter declares the property and fills it.لای چەپ، شێوە درێژەکەی کلاسی Product: دوو ناساندنی تایبەتمەندی، دروستکەرێک بە پارامیتەرەکانی string $name و int $price و دوو دێڕی $this->name = $name; و $this->price = $price;. لای ڕاست، شێوە کورتەکە بۆ PHP 8.0 و دواتر: public function __construct(public string $name, public int $price) {}. نیشانەی یەکسانی لە نێوانیاندا. تێبینی: public لە پێش پارامیتەرێک تایبەتمەندییەکە دەناسێنێت و پڕی دەکاتەوە.
Promotion writes each property once instead of three times. هەر یەک جار دەنووسێت لەبری سێ جار.CêIT

Types on properties and parametersجۆر لەسەر تایبەتمەندییەکان و پارامیتەرەکان

int, string, float, bool, array or a class name written before a property or a parameter is a . PHP checks it while the script runs (typed properties exist since PHP 7.4). What happens to a value that does not fit?

int، string، float، bool، array یان ناوی کە لە پێش یان دەنووسرێت . PHP لە کاتی کارکردنی دەیپشکنێت ( جۆردار لە ⁦PHP 7.4⁩ـەوە هەن). ئەو نەگونجێت چی بەسەر دێت؟

A string where an int is expectedزنجیرەنووسەیەک لە شوێنی inttypes.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public function __construct(
        public string $name,
        public int $price,
    ) {}
}

$a = new Product("Tea", "5000");    // a string that looks like a whole number
var_dump($a->price);

$b = new Product("Tea", "five thousand");
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 10-11

"5000" looks like a whole number, so PHP converts it to the int 5000.

⁦"5000"⁩ وەک دەچێت، بۆیە PHP دەیگۆڕێت بۆ ⁦int 5000⁩.

Lineدێڕی 13

"five thousand" cannot become an int: a TypeError stops the script.

⁦"five thousand"⁩ ناتوانێت ببێتە int: TypeErrorـێک ڕادەگرێت.

By default PHP is forgiving and converts values that clearly fit (the same type juggling as in Data types). With declare(strict_types=1); as the first statement of the file, PHP stops converting, and even "5000" is refused:

بە شێوەی بنەڕەتی PHP لێبووردەیە و ئەو دەگۆڕێت کە بە ڕوونی دەگونجێن (هەمان گۆڕینی خۆکاری جۆر کە لە جۆرەکانی دراوەدا بینیت). بە declare(strict_types=1); وەک یەکەم دێڕی ، PHP واز لە گۆڕین دەهێنێت و تەنانەت "5000"ـیش ڕەت دەکرێتەوە:

strict_types: no conversion⁦strict_types⁩: بێ گۆڕینtypes_strict.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
declare(strict_types=1);

class Product
{
    public function __construct(
        public string $name,
        public int $price,
    ) {}
}

$a = new Product("Tea", "5000");
A purple gate marked int $price. Three inputs go through it: 5000 is an int and is accepted ($price = 5000); "5000" is text that looks like a whole number and is converted to 5000, but with declare(strict_types=1) it gives a TypeError; "five thousand" is not a number and is refused with a TypeError. Bottom: PHP checks the type while the script runs.دەروازەیەکی مۆر کە int $priceـی لەسەرە. سێ نرخ پێیدا تێدەپەڕن: 5000 ژمارەی تەواوە و وەردەگیرێت ($price = 5000)؛ "5000" زنجیرەنووسەیەکە کە وەک ژمارەی تەواو دەچێت و دەگۆڕدرێت بۆ 5000، بەڵام بە declare(strict_types=1) هەڵەی TypeError دەدات؛ "five thousand" ژمارە نییە و بە TypeError ڕەت دەکرێتەوە. خوارەوە: PHP لە کاتی کارکردنی دەسنووسەکەدا جۆرەکە دەپشکنێت.
A type declaration guards the property. پاسەوانی دەکات.CêIT

public, private and protectedpublic، private و protected

Every property, method and constant has a visibility, also called an . public: any code may use it. private: only code inside the same class. protected: the class and its child classes (next lesson). A method or constant written without one is public, but always write the word yourself.

هەموو ، و هەیە. public: هەموو کۆدێک دەتوانێت بەکاری بهێنێت. private: تەنیا کۆدی ناو هەمان . protected: و (وانەی داهاتوو). یان کە بەبێ ئەم وشەیە نووسرابێت publicـە، بەڵام هەمیشە خۆت وشەکە بنووسە.

Good classes keep their data private and let public methods guard it. This is : below, nobody can set a price of zero or less, because the only way in is setPrice(), which checks the value. The same idea in other languages: Java and Python.

باش خۆیان private دەهێڵنەوە و ڕێگە دەدەن public پاسەوانی بکەن. ئەمە : لە خوارەوە کەس ناتوانێت نرخی سفر یان کەمتر دابنێت، چونکە تاکە ڕێگەی چوونەژوورەوە setPrice()ـە کە دەپشکنێت. هەمان بیرۆکە لە زمانەکانی تردا: Java و Python.

A private price and a guarding methodنرخێکی private و میتۆدێکی پاسەوانvisibility.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public function __construct(
        public string $name,
        private int $price,
    ) {}

    public function price(): int          // a getter: read the price
    {
        return $this->price;
    }

    public function setPrice(int $newPrice): bool
    {
        if ($newPrice <= 0) {
            return false;                  // refuse: the price stays as it was
        }
        $this->price = $newPrice;
        return true;
    }
}

$tea = new Product("Tea", 5000);
var_dump($tea->setPrice(-100));   // refused
var_dump($tea->setPrice(6000));   // accepted
echo $tea->price(), "\n";
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 6

private: only Product's own methods may read or change $price.

private: تەنیا خودی Product دەتوانن $price بخوێننەوە یان بیگۆڕن.

Lineدێڕی 9-12

A : the public way to read the price.

: ڕێگە publicـەکە بۆ خوێندنەوەی نرخەکە.

Lineدێڕی 14-21

A that refuses bad values.

کە خراپ ڕەت دەکاتەوە.

A shop counter. Left: outside the class, other code as a customer, writing $tea->name, $tea->price() and $tea->setPrice(6000). Middle, in green: public, the shelf anyone may use, holding name, price() and setPrice(); an arrow with a tick reaches it from the customer. A thick line is the counter. Right, in orange: private, behind the counter, only the class's own methods, holding $price and costPrice() with padlocks, and the shopkeeper; a dashed arrow shows that setPrice() may change $price. Bottom: public, all code can use it; private, only code inside the same class; protected, the class and its child classes (next lesson).پێشخانی دووکانێک. لای چەپ: دەرەوەی کلاسەکە، کۆدی تر وەک کڕیارێک کە $tea->name، $tea->price() و $tea->setPrice(6000) دەنووسێت. ناوەڕاست، بە سەوز: public، ئەو ڕەفەی هەموو کەس بەکاری دەهێنێت، name، price() و setPrice()ـی لەسەرە؛ تیرێک بە نیشانەی ڕاست لە کڕیارەکەوە پێی دەگات. هێڵێکی ئەستوور پێشخانەکەیە. لای ڕاست، بە پرتەقاڵی: private، پشتی پێشخانەکە، تەنیا میتۆدەکانی خودی کلاسەکە، $price و costPrice() بە قفڵەوە و دووکاندارەکە؛ تیرێکی پچڕپچڕ پیشانی دەدات کە setPrice() دەتوانێت $price بگۆڕێت. خوارەوە: public، هەموو کۆدێک بەکاری دەهێنێت؛ private، تەنیا کۆدی ناو هەمان کلاس؛ protected، کلاسەکە و کلاسەکانی منداڵ (وانەی داهاتوو).
public is the shelf; private is behind the counter.public ڕەفەکەیە؛ private پشتی پێشخانەکەیە.CêIT

public, private and protectedpublic، private و protected

Common mistake: using private members from outsideهەڵەی باو: بەکارهێنانی بەشە privateـەکان لە دەرەوە

Writing a private property or calling a private method from outside the class stops the script. Read the message: it names the class and the member.

نووسینی private یان بانگکردنی private لە دەرەوەی ڕادەگرێت. پەیامەکە بخوێنەرەوە: ناوی و بەشەکە دەڵێت.

Writing a private propertyنووسینی تایبەتمەندییەکی privateprivate_property.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public function __construct(
        public string $name,
        private int $price,
    ) {}
}

$tea = new Product("Tea", 5000);
$tea->price = -100;   // from outside the class
Calling a private methodبانگکردنی میتۆدێکی privateprivate_method.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public function __construct(
        public string $name,
        private int $price,
    ) {}

    private function costPrice(): int   // the shop's secret
    {
        return intdiv($this->price * 80, 100);
    }
}

$tea = new Product("Tea", 5000);
echo $tea->costPrice();

The fix is not to make everything public. Use the public methods the class offers (price(), setPrice()), or add a new public method that does the job safely.

چارەسەرەکە ئەوە نییە هەموو شتێک بکەیتە public. publicـی بەکار بهێنە (price()، setPrice()) یان publicـی نوێ زیاد بکە کە کارەکە بە سەلامەتی دەکات.

readonly: set once, never changed (PHP 8.1)readonly: یەک جار دادەنرێت، هەرگیز ناگۆڕێت ⁦(PHP 8.1)⁩

Some values must never change after the object exists: a product code, an order number. A (PHP 8.1) can be written exactly once, from inside its class, usually by the constructor. It must have a type and cannot have a default value. A normal property beside it can still change.

هەندێک نابێت دوای دروستبوونی بگۆڕێن: کۆدی بەرهەم، ژمارەی داواکاری. ⁦(PHP 8.1)⁩ تەنیا یەک جار دەنووسرێت، لە ناو خۆیەوە، زۆرجار لەلایەن . دەبێت جۆری هەبێت و ناتوانێت هەبێت. ئاسایی لە تەنیشتیدا هێشتا دەتوانێت بگۆڕێت.

A product code that cannot changeکۆدێکی بەرهەم کە ناگۆڕێتreadonly.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public function __construct(
        public readonly string $code,
        public string $name,
    ) {}
}

$tea = new Product("TEA-001", "Tea");
$tea->name = "Black tea";      // fine: name is not readonly
echo $tea->code, " ", $tea->name, "\n";
$tea->code = "TEA-002";        // not allowed
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 5

readonly: written once, by the constructor.

readonly: یەک جار دەنووسرێت، لەلایەن .

Lineدێڕی 11

name is a normal property: changing it is fine.

name ئاساییە: گۆڕینی کێشە نییە.

Lineدێڕی 13

A second write to code stops the script.

نووسینی دووەمی code ڕادەگرێت.

Top row, public readonly string $code: new Product("TEA-001", "Tea") leads to code = "TEA-001" with a padlock, then $tea->code = "TEA-002"; ends in a cross and Error: Cannot modify readonly. Labels: 1. the constructor writes it; 2. now it is locked; 3. changing it stops the script. Bottom row, public string $name: name = "Tea", then $tea->name = "Black tea"; with a tick gives name = "Black tea". Bottom: use readonly for values that must never change, such as a product code.ڕیزی سەرەوە، public readonly string $code: new Product("TEA-001", "Tea") دەگاتە code = "TEA-001" بە قفڵێکەوە، پاشان $tea->code = "TEA-002"; بە خاچێک و Error: Cannot modify readonly کۆتایی دێت. ڕوونکردنەوەکان: ١. دروستکەرەکە دەینووسێت؛ ٢. ئێستا قفڵ دراوە؛ ٣. گۆڕینی دەسنووسەکە ڕادەگرێت. ڕیزی خوارەوە، public string $name: name = "Tea"، پاشان $tea->name = "Black tea"; بە نیشانەی ڕاست name = "Black tea" دەدات. خوارەوە: readonly بۆ ئەو نرخانە بەکار بهێنە کە هەرگیز نابێت بگۆڕێن، وەک کۆدی بەرهەم.
A readonly property: written once, then locked.: یەک جار دەنووسرێت، پاشان قفڵ دەدرێت.CêIT

static: members that belong to the classstatic: ئەو بەشانەی هی کلاسەکەن

A normal property belongs to each object. A static property belongs to the class itself: there is one copy, shared by every object. You reach it with ::, the : Product::$count outside the class, self::$count inside it. A static method, such as Product::count(), needs no object, so there is no $this inside it. These are ; Java has the same idea (static members).

ئاسایی هی هەر . static هی خودی : یەک کۆپی هەیە کە هەموو هاوبەشی دەکەن. بە :: پێی دەگەیت، کە : Product::$count لە دەرەوەی و self::$count لە ناوەوەی. static، وەک Product::count()، پێویستی بە نییە، بۆیە $this لە ناویدا نییە. ئەمانە ؛ Javaـش هەمان بیرۆکەی هەیە (ئەندامە ستاتیکەکان).

Counting products with a static propertyژماردنی بەرهەمەکان بە تایبەتمەندییەکی staticstatic_members.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public const CURRENCY = "IQD";       // a class constant
    private static int $count = 0;       // one counter for the whole class

    public function __construct(
        public string $name,
        public int $price,
    ) {
        self::$count++;                   // :: reaches the class itself
    }

    public static function count(): int  // a static method
    {
        return self::$count;
    }

    public function label(): string
    {
        return $this->name . ": " . number_format($this->price) . " " . self::CURRENCY;
    }
}

echo Product::count(), " products\n";
$tea = new Product("Tea", 5000);
$rice = new Product("Rice 5 kg", 12000);
echo Product::count(), " products\n";
echo $rice->label(), "\n";
echo Product::CURRENCY, "\n";
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 4

A : a fixed value of the class.

: جێگیری .

Lineدێڕی 5

One counter for the whole class, not one per object.

یەک ژمێرەر بۆ هەموو ، نەک یەک بۆ هەر .

Lineدێڕی 11

Every constructor call adds one to the shared counter.

هەر بانگکردنێکی یەک بۆ ژمێرەرە هاوبەشەکە زیاد دەکات.

Lineدێڕی 25

Product::count() works before any object exists.

Product::count() پێش بوونی هیچ کار دەکات.

The class Product, in purple, holds what is shared by every product: const CURRENCY = "IQD" and static $count = 2. Below it two objects, $tea (name "Tea", price 5000) and $rice (name "Rice 5 kg", price 12000), each with its own name and price. Dashed arrows marked self::$count++ go from both objects up to the one counter. Product::count() gives 2. Bottom: read class members with :: and the class name, as in Product::count() (inside: self::$count).کلاسی Product، بە مۆر، ئەوەی هەڵگرتووە کە بۆ هەموو بەرهەمێک هاوبەشە: const CURRENCY = "IQD" و static $count = 2. لە خوارەوەی دوو ئۆبجێکت: $tea (name "Tea"، price 5000) و $rice (name "Rice 5 kg"، price 12000)، هەریەکەیان name و priceـی خۆی هەیە. تیری پچڕپچڕ کە self::$count++ـی لەسەرە لە هەردوو ئۆبجێکتەکەوە بۆ تاکە ژمێرەرەکە دەچن. Product::count() ژمارە 2 دەدات. خوارەوە: بەشەکانی کلاس بە :: و ناوی کلاسەکە بخوێنەرەوە، وەک Product::count() (لە ناوەوە: self::$count).
static and const: one copy, owned by the class.static و const: یەک کۆپی کە هی .CêIT

static: members that belong to the classstatic: ئەو بەشانەی هی کلاسەکەن

Class constants, and -> or ::نەگۆڕەکانی کلاس و هەڵبژاردنی -> یان ::

public const CURRENCY = "IQD"; is a : a fixed value that belongs to the class. It has no $, is usually written in capitals and is read with Product::CURRENCY outside the class or self::CURRENCY inside it. (Constants outside classes are in Constants and scope.) PHP 8.3 also allows a type on a class constant, public const string CURRENCY = "IQD";, which PHP 8.2 does not accept.

public const CURRENCY = "IQD"; : جێگیرە کە هی . $ـی نییە، زۆرجار بە پیتی گەورە دەنووسرێت و بە Product::CURRENCY لە دەرەوەی یان self::CURRENCY لە ناوەوەی دەخوێندرێتەوە. ( لە دەرەوەی لە نەگۆڕەکان و مەودادان.) ⁦PHP 8.3⁩ ڕێگە بە جۆریش لەسەر دەدات، public const string CURRENCY = "IQD";، کە ⁦PHP 8.2⁩ قبووڵی ناکات.

Two panels. Left, in green, the arrow ->: it belongs to one object, for example $tea->name, $tea->label() and $this->price; this is the object operator. Right, in blue, the double colon ::: it belongs to the class itself, for example Product::CURRENCY, Product::count(), self::$count and parent::__construct(); this is the scope resolution operator. Bottom: a property name after :: keeps its $ (self::$count); after -> it has none ($this->price).دوو بەش. لای چەپ، بە سەوز، تیری ->: هی یەک ئۆبجێکتە، بۆ نموونە $tea->name، $tea->label() و $this->price؛ ئەمە کارپێکەری ئۆبجێکتە. لای ڕاست، بە شین، ::: هی خودی کلاسەکەیە، بۆ نموونە Product::CURRENCY، Product::count()، self::$count و parent::__construct()؛ ئەمە کارپێکەری دیاریکردنی مەودایە. خوارەوە: ناوی تایبەتمەندی لە دوای :: نیشانەی $ دەهێڵێتەوە (self::$count)؛ لە دوای تیرەکە نایهێڵێتەوە ($this->price).
-> for one object, :: for the class.-> بۆ یەک ، :: بۆ .CêIT

A static method has no object, so $this inside it is an error:

static هیچ نییە، بۆیە $this لە ناویدا هەڵەیە:

$this inside a static method⁦$this⁩ لە ناو میتۆدێکی staticstatic_this.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public string $name = "Tea";

    public static function shout(): string
    {
        return strtoupper($this->name);   // no object here
    }
}

echo Product::shout();

Worked example: the bazaar cartنموونەی کارپێکراو: سەبەتەی بازاڕ

The task. A small bazaar shop wants a page that prints a receipt: every product with its quantity and cost, then the total. The plan. Two classes. Product keeps a name that never changes (readonly), a private price with a getter, the constant CURRENCY and a static helper money() that formats an amount. Cart keeps a private array of lines and has three methods: add(), total() and receipt(). A cart has products; it is not a kind of product, so it holds Product objects instead of copying their code ().

ئەرکەکە. دووکانێکی بچووکی بازاڕ لاپەڕەیەکی دەوێت پسوولەیەک چاپ بکات: هەموو بەرهەمێک بە ژمارە و تێچووەکەیەوە، پاشان کۆی گشتی. پلانەکە. دوو . Product ناوێک هەڵدەگرێت کە هەرگیز ناگۆڕێت (readonly)، نرخێکی private بە ، CURRENCY و یارمەتیدەری static بە ناوی money() کە بڕێک پارە ڕێک دەخات. Cart privateـی دێڕەکان هەڵدەگرێت و سێ هەیە: add()، total() و receipt(). سەبەتە بەرهەمی تێدایە؛ جۆرێک لە بەرهەم نییە، بۆیە Product هەڵدەگرێت لەبری ئەوەی کۆدەکەیان کۆپی بکات ().

Product and CartProduct و Cartcart.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public const CURRENCY = "IQD";

    public function __construct(
        public readonly string $name,
        private int $price,
    ) {}

    public function price(): int
    {
        return $this->price;
    }

    public static function money(int $amount): string
    {
        return number_format($amount) . " " . self::CURRENCY;
    }
}

class Cart
{
    private array $lines = [];   // each line: a product and a quantity

    public function add(Product $product, int $qty = 1): void
    {
        $this->lines[] = ["product" => $product, "qty" => $qty];
    }

    public function total(): int
    {
        $sum = 0;
        foreach ($this->lines as $line) {
            $sum += $line["product"]->price() * $line["qty"];
        }
        return $sum;
    }

    public function receipt(): string
    {
        $text = "";
        foreach ($this->lines as $line) {
            $p = $line["product"];
            $cost = $p->price() * $line["qty"];
            $text .= sprintf("%-12s x%d %14s\n", $p->name, $line["qty"], Product::money($cost));
        }
        return $text . sprintf("%-15s %14s\n", "Total", Product::money($this->total()));
    }
}

$tea   = new Product("Tea", 5000);
$rice  = new Product("Rice 5 kg", 12000);
$honey = new Product("Honey", 15000);

$cart = new Cart();
$cart->add($tea, 2);
$cart->add($rice);
$cart->add($honey);

echo $cart->receipt();
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 7-8

The name can be read by anyone but never changed; the price is private.

ناوەکە هەموو کەس دەیخوێنێتەوە، بەڵام هەرگیز ناگۆڕێت؛ نرخەکە privateـە.

Lineدێڕی 16-19

A static helper: Product::money(37000) gives "37,000 IQD" without any object.

یارمەتیدەرێکی static: Product::money(37000) بێ هیچ ⁦"37,000 IQD"⁩ دەدات.

Lineدێڕی 24

Only Cart's own methods can change the lines.

تەنیا خودی Cart دەتوانن دێڕەکان بگۆڕن.

Lineدێڕی 26

Product $product: the type declaration accepts only Product objects; $qty has the default value 1.

Product $product: تەنیا Product وەردەگرێت؛ $qty 1ـی هەیە.

Lineدێڕی 35

The cart asks each product for its price with ->price(); it never touches the private property.

سەبەتەکە بە ->price() نرخی هەر بەرهەمێک دەپرسێت؛ هەرگیز دەست لە privateـەکە نادات.

Lineدێڕی 46

sprintf lines the columns up: %-12s pads the name to 12 characters.

sprintf ستوونەکان ڕێک دەخات: %-12s ناوەکە دەگەیەنێتە ⁦12⁩ پیت.

An animation in five steps. Left, three Product objects: $tea (Tea: 5,000 IQD), $rice (Rice 5 kg: 12,000 IQD) and $honey (Honey: 15,000 IQD). Right, the object $cart of class Cart with its private array $lines and total(). Step 1: $cart = new Cart(); the cart is empty, total 0. Step 2: $cart->add($tea, 2); the line Tea x2 10,000 IQD appears, total 10,000. Step 3: $cart->add($rice); no quantity, so the default 1 is used, total 22,000. Step 4: $cart->add($honey); total 37,000, because total() asks every product for its price. Step 5: echo $cart->receipt(); data and methods live together in one object.
An animation in five steps. Left, three Product objects: $tea (Tea: 5,000 IQD), $rice (Rice 5 kg: 12,000 IQD) and $honey (Honey: 15,000 IQD). Right, the object $cart of class Cart with its private array $lines and total(). Step 1: $cart = new Cart(); the cart is empty, total 0. Step 2: $cart->add($tea, 2); the line Tea x2 10,000 IQD appears, total 10,000. Step 3: $cart->add($rice); no quantity, so the default 1 is used, total 22,000. Step 4: $cart->add($honey); total 37,000, because total() asks every product for its price. Step 5: echo $cart->receipt(); data and methods live together in one object.
Filling the cart, one call at a time.پڕکردنی سەبەتەکە، یەک بانگکردن لە هەر جارێکدا.CêIT

Worked example: the bazaar cartنموونەی کارپێکراو: سەبەتەی بازاڕ

Objects are shared, not copiedئۆبجێکتەکان هاوبەش دەکرێن، کۆپی ناکرێن

$same = $tea; does not copy the object. Both variables now hold a handle to the same object, so a change made through one is seen through the other. Objects passed to a method, as in $cart->add($tea), travel the same way: the cart sees a later price change. Arrays behave differently: they are copied (pass by value). To get a real second object, use clone. Java works the same way (two variables, one object).

$same = $tea; کۆپی ناکات. ئێستا هەردوو دەسکێک بۆ هەمان هەڵدەگرن، بۆیە گۆڕانکارییەک کە لە ڕێگەی یەکێکیانەوە بکرێت لە ڕێگەی ئەوی تریشەوە دەبینرێت. ئەو دەدرێنە ، وەک لە $cart->add($tea)ـدا، بە هەمان شێوە دەڕۆن: سەبەتەکە گۆڕینی دواتری نرخ دەبینێت. جیاوازن: کۆپی دەکرێن (ناردن بە نرخ). بۆ دووەمی ڕاستەقینە clone بەکار بهێنە. Javaـش بە هەمان شێوە کار دەکات (دوو گۆڕاو، یەک ئۆبجێکت).

Two names for one object, and cloneدوو ناو بۆ یەک ئۆبجێکت و clonehandles.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public function __construct(
        public string $name,
        public int $price,
    ) {}
}

$tea = new Product("Tea", 5000);
$same = $tea;            // copies the handle, not the object
$same->price = 6000;
echo $tea->price, "\n";  // 6000: one object, two names

$copy = clone $tea;      // a real second object
$copy->price = 7000;
echo $tea->price, "\n";  // still 6000
echo $copy->price, "\n";
var_dump($same === $tea, $copy === $tea);
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 11-13

$same and $tea are the same object, so $tea->price becomes 6000.

$same و $tea هەمان ، بۆیە $tea->price دەبێتە ⁦6000⁩.

Lineدێڕی 15-18

clone makes a new object; changing the copy leaves $tea alone.

clone نوێ دروست دەکات؛ گۆڕینی کۆپییەکە دەست لە $tea نادات.

Lineدێڕی 19

=== on objects asks: is it the very same object?

=== لەسەر دەپرسێت: ئایا ڕێک هەمان ؟

Left, three variables: $tea, $same and $copy. Arrows from $tea and $same both point to object 1 (name "Tea", price 6000), with the code $same = $tea;. An arrow from $copy points to object 2 (name "Tea", price 7000), with the code $copy = clone $tea;, and a dashed arrow marked clone goes from object 1 to object 2. Bottom: $same = $tea; copies the handle, one object with two names; clone $tea makes a second, separate object.لای چەپ، سێ گۆڕاو: $tea، $same و $copy. تیرەکانی $tea و $same هەردووکیان ئاماژە بۆ ئۆبجێکتی 1 دەکەن (name "Tea"، price 6000)، بە کۆدی $same = $tea;. تیرێک لە $copyـەوە ئاماژە بۆ ئۆبجێکتی 2 دەکات (name "Tea"، price 7000)، بە کۆدی $copy = clone $tea; و تیرێکی پچڕپچڕ کە cloneـی لەسەرە لە ئۆبجێکتی 1ـەوە بۆ ئۆبجێکتی 2 دەچێت. خوارەوە: $same = $tea; دەسکەکە کۆپی دەکات، یەک ئۆبجێکت بە دوو ناو؛ clone $tea ئۆبجێکتێکی دووەمی جیا دروست دەکات.
Assignment shares the object; clone copies it.یەکسانکردن هاوبەش دەکات؛ clone کۆپی دەکات.CêIT

Common mistakesهەڵە باوەکان

Every message below was produced by PHP 8.2. The message names the class and the member, so read it before you change anything.

هەموو پەیامەکانی خوارەوە ⁦PHP 8.2⁩ دروستی کردوون. پەیامەکە ناوی و بەشەکە دەڵێت، بۆیە پێش ئەوەی هیچ بگۆڕیت بیخوێنەرەوە.

Mistakes with classes and objects, and PHP 8.2's real messages.هەڵەکان لەگەڵ و و پەیامە ڕاستەقینەکانی ⁦PHP 8.2⁩.
MistakeهەڵەWhat PHP saysPHP چی دەڵێتFixچاککردن
$tea = Product("Tea", 5000);Error: Call to undefined function Product()Write new Product("Tea", 5000).new Product("Tea", 5000) بنووسە.
function _construct(...)Error: Typed property Product::$name must not be accessed before initializationOne underscore: the constructor never ran. Write __construct with two.یەک هێڵی ژێرەوە: هەرگیز جێبەجێ نەبوو. __construct بە دوو هێڵ بنووسە.
echo $tea->label;Warning: Undefined property: Product::$labelA method needs brackets: $tea->label(). کەوانەی دەوێت: $tea->label().
return $name; // in a methodWarning: Undefined variable $nameUse the property: $this->name. بەکار بهێنە: $this->name.
echo $tea->count; // staticNotice: Accessing static property Product::$count as non staticStatic members use ::: Product::$count or a static method. :: بەکار دەهێنن: Product::$count یان static.
$this in a static methodError: Using $this when not in object contextMake the method non-static, or use self:: for class members. بکە بە ناستاتیک، یان self:: بۆ بەشەکانی بەکار بهێنە.
$tea->price = -100; // privateError: Cannot access private property Product::$priceUse the public method: $tea->setPrice(6000). publicـەکە بەکار بهێنە: $tea->setPrice(6000).
$tea->code = "TEA-002"; // readonlyError: Cannot modify readonly property Product::$codeGive the value once, in the constructor; make a new object if it must differ. یەک جار لە بدە؛ ئەگەر دەبێت جیاواز بێت نوێ دروست بکە.
The one-underscore constructor in fullنموونە تەواوەکەی دروستکەر بە یەک هێڵی ژێرەوەone_underscore.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public string $name;

    public function _construct(string $name)   // only ONE underscore
    {
        $this->name = $name;
    }
}

$tea = new Product("Tea");
echo $tea->name;

PHP 8.2 here, the same on 8.3, 8.4 and 8.5⁦PHP 8.2⁩ لێرە، هەمان شت لەسەر ⁦8.3⁩، ⁦8.4⁩ و ⁦8.5⁩

Every example in this lesson ran on PHP 8.2, the version in the course's XAMPP, and works the same on PHP 8.3, 8.4 and 8.5. Newer versions only add features: typed class constants and the #[\Override] check (8.3), property hooks, public private(set) and new Product("Tea", 5000)->label() without extra brackets (8.4), and clone with new values (8.5). As of November 2026, PHP 8.4 and 8.5 are actively supported, and 8.2 receives only security fixes until 31 December 2026, so choose a supported version when you install XAMPP or rent hosting.

هەموو نموونەکانی ئەم وانەیە لەسەر ⁦PHP 8.2⁩ جێبەجێ کران، کە وەشانی XAMPPـی خولەکەیە و لەسەر ⁦PHP 8.3⁩، ⁦8.4⁩ و ⁦8.5⁩ بە هەمان شێوە کار دەکەن. وەشانە نوێکان تەنیا تایبەتمەندی زیاد دەکەن: جۆر لەسەر و پشکنینی #[\Override] ⁦(8.3)⁩، property hooks، public private(set) و new Product("Tea", 5000)->label() بێ کەوانەی زیادە ⁦(8.4)⁩ و clone بە نوێ ⁦(8.5)⁩. تا نۆڤەمبەری ⁦2026⁩، ⁦PHP 8.4⁩ و ⁦8.5⁩ پشتگیریی چالاکیان هەیە و ⁦8.2⁩ تەنیا تا ⁦31⁩ی دیسەمبەری ⁦2026⁩ چاککردنەوەی ئاسایش وەردەگرێت، بۆیە کاتێک XAMPP دادەمەزرێنیت یان هۆستینگ بەکرێ دەگریت وەشانێکی پشتگیریکراو هەڵبژێرە.

A timeline of object-oriented PHP: PHP 5.0 (2004) visibility, __construct and interfaces; PHP 5.4 (2012) traits; PHP 7.4 (2019) typed properties; PHP 8.0 (2020) constructor promotion; PHP 8.1 (2021) readonly and enums; PHP 8.2 (2022) readonly classes, marked as the XAMPP version that runs every example here; PHP 8.3 (2023) typed constants and #[Override]; PHP 8.4 (2024) property hooks and asymmetric visibility; PHP 8.5 (2025) clone with. Bottom: as of November 2026, PHP 8.4 and 8.5 are actively supported; 8.2 gets security fixes until 31 December 2026.هێڵی کاتی PHPـی تەنخواز: PHP 5.0 (2004) visibility، __construct و interfaces؛ PHP 5.4 (2012) traits؛ PHP 7.4 (2019) typed properties؛ PHP 8.0 (2020) constructor promotion؛ PHP 8.1 (2021) readonly و enums؛ PHP 8.2 (2022) readonly classes، کە وەک وەشانی XAMPP دیار کراوە و هەموو نموونەکانی ئێرە جێبەجێ دەکات؛ PHP 8.3 (2023) typed constants و #[Override]؛ PHP 8.4 (2024) property hooks و asymmetric visibility؛ PHP 8.5 (2025) clone with. خوارەوە: تا نۆڤەمبەری 2026، PHP 8.4 و 8.5 پشتگیریی چالاکیان هەیە؛ 8.2 تا 31ی دیسەمبەری 2026 تەنیا چاککردنەوەی ئاسایش وەردەگرێت.
Object-oriented PHP grew step by step.PHPـی تەنخواز هەنگاو بە هەنگاو گەشەی کرد.CêIT

Exercisesڕاهێنانەکان

Exerciseڕاهێنان1. A Student class١. کلاسی Student

Write a class Student with a promoted public name and a private array of marks that starts empty. Add addMark(int $mark) and average(): float, which returns 0.0 when there are no marks. Give Lana the marks 78, 91 and 85, print her average with one decimal place, then print the average of Soran, who has no marks.

Student بنووسە بە nameـێکی publicـی بەرزکراوە و privateـی نمرەکان کە بە بەتاڵی دەست پێ دەکات. addMark(int $mark) و average(): float زیاد بکە کە ئەگەر هیچ نمرەیەک نەبێت ⁦0.0⁩ دەگەڕێنێتەوە. نمرەکانی ⁦78⁩، ⁦91⁩ و ⁦85⁩ بدە بە لانا، تێکڕاکەی بە یەک ژمارەی دوای خاڵ چاپ بکە، پاشان تێکڕای سۆران چاپ بکە کە هیچ نمرەیەکی نییە.

Hintئاماژە

count($this->marks) gives the number of marks; check it before you divide.

count($this->marks) ژمارەی نمرەکان دەدات؛ پێش دابەشکردن بیپشکنە.

Show answerوەڵامەکە پیشان بدە

The marks stay private; the class guards the empty case so that it never divides by zero.

نمرەکان privateـن؛ ئاگای لە دۆخی بەتاڵە بۆ ئەوەی هەرگیز دابەشکردن بەسەر سفردا نەکات.

ex_student.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Student
{
    public function __construct(
        public string $name,
        private array $marks = [],
    ) {}

    public function addMark(int $mark): void
    {
        $this->marks[] = $mark;
    }

    public function average(): float
    {
        if (count($this->marks) === 0) {
            return 0.0;
        }
        return array_sum($this->marks) / count($this->marks);
    }
}

$lana = new Student("Lana");
$lana->addMark(78);
$lana->addMark(91);
$lana->addMark(85);
printf("%s: %.1f\n", $lana->name, $lana->average());

$soran = new Student("Soran");
printf("%s: %.1f\n", $soran->name, $soran->average());
Exerciseڕاهێنان2. Find the three mistakes٢. سێ هەڵەکە بدۆزەرەوە

This tea-house class has three mistakes. Find them using PHP's messages, then fix them so that the program prints Tea with 3 spoons of sugar.

ئەم چایخانەیە سێ هەڵەی تێدایە. بە یارمەتیی پەیامەکانی PHP بیاندۆزەرەوە، پاشان چاکیان بکە بۆ ئەوەی ⁦Tea with 3 spoons of sugar⁩ چاپ بکات.

ex_bugs.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class TeaGlass
{
    private int $sugar = 0;

    public function addSugar(int $spoons): void
    {
        $sugar = $sugar + $spoons;
    }

    public function describe(): string
    {
        return "Tea with " . $this->sugar . " spoons of sugar";
    }
}

$glass = TeaGlass();
$glass->addSugar(2);
$glass->sugar = 5;
echo $glass->describe();
Hintئاماژە

Run it after each fix: PHP reports the first fatal error only.

دوای هەر چاککردنێک جێبەجێی بکە: PHP تەنیا یەکەم ڕادەگەیەنێت.

Show answerوەڵامەکە پیشان بدە

Run 1 stops at line 17, Call to undefined function TeaGlass(): new is missing. After adding it, run 2 shows Warning: Undefined variable $sugar (line 8: $this-> is missing) and then Cannot access private property TeaGlass::$sugar (line 19: outside code may not write a private property). The fixed program adds the sugar through the public method:

جێبەجێکردنی یەکەم لە دێڕی ⁦17⁩ ڕادەوەستێت، ⁦Call to undefined function TeaGlass()⁩: new نییە. دوای زیادکردنی، جێبەجێکردنی دووەم ⁦Warning: Undefined variable $sugar⁩ پیشان دەدات (دێڕی 8: $this-> نییە) و پاشان ⁦Cannot access private property TeaGlass::$sugar⁩ (دێڕی ⁦19⁩: کۆدی دەرەوە ناتوانێت private بنووسێت). بەرنامە چاککراوەکە شەکرەکە لە ڕێگەی publicـەکەوە زیاد دەکات:

ex_bugs_fixed.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class TeaGlass
{
    private int $sugar = 0;

    public function addSugar(int $spoons): void
    {
        $this->sugar = $this->sugar + $spoons;   // fix 1: $this->
    }

    public function describe(): string
    {
        return "Tea with " . $this->sugar . " spoons of sugar";
    }
}

$glass = new TeaGlass();     // fix 2: new
$glass->addSugar(2);
$glass->addSugar(1);         // fix 3: change sugar through a public method
echo $glass->describe(), "\n";
Exerciseڕاهێنان3. A taxi fare٣. کرێی تەکسی

Write TaxiRide with readonly from and to, a private km, the constants START_FARE = 2000 and PER_KM = 500, and a static counter of rides. fare() returns the start fare plus 500 dinars per kilometre, rounded to a whole number. Make three rides (4.5 km, 11 km and 12.2 km), print each fare and then the number of rides.

TaxiRide بنووسە بە from و toـی readonly، kmـێکی private، START_FARE = 2000 و PER_KM = 500 و ژمێرەرێکی static بۆ گەشتەکان. fare() کرێی دەستپێک لەگەڵ ⁦500⁩ دینار بۆ هەر کیلۆمەترێک دەگەڕێنێتەوە، بە . سێ گەشت دروست بکە (⁦4.5 km⁩، ⁦11 km⁩ و ⁦12.2 km⁩)، کرێی هەریەکەیان و پاشان ژمارەی گەشتەکان چاپ بکە.

Hintئاماژە

(int) round($this->km * self::PER_KM) gives a whole number of dinars.

(int) round($this->km * self::PER_KM) بڕی دینارەکە وەک دەدات.

Show answerوەڵامەکە پیشان بدە

Constants and the counter belong to the class (self::), the distance belongs to each ride ($this->).

و ژمێرەرەکە هی (self::)، دوورییەکە هی هەر گەشتێکە ($this->).

ex_taxi.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class TaxiRide
{
    public const START_FARE = 2000;   // dinars when the ride starts
    public const PER_KM = 500;        // dinars for every kilometre
    private static int $rides = 0;

    public function __construct(
        public readonly string $from,
        public readonly string $to,
        private float $km,
    ) {
        self::$rides++;
    }

    public function fare(): int
    {
        return self::START_FARE + (int) round($this->km * self::PER_KM);
    }

    public static function rides(): int
    {
        return self::$rides;
    }
}

$trips = [
    new TaxiRide("Bazaar", "University", 4.5),
    new TaxiRide("University", "Airport", 11),
    new TaxiRide("Airport", "Bazaar", 12.2),
];
foreach ($trips as $t) {
    echo "$t->from -> $t->to: ", number_format($t->fare()), " IQD\n";
}
echo TaxiRide::rides(), " rides\n";
Exerciseڕاهێنان4. Grow the cart٤. سەبەتەکە گەورەتر بکە

Add two methods to the cart of the worked example: count(), the number of items (the sum of the quantities), and remove(string $name), which deletes the lines of that product. Test it with 2 × Tea and 1 × Honey, then remove the tea.

دوو بۆ سەبەتەی نموونە کارپێکراوەکە زیاد بکە: count()، ژمارەی کاڵاکان (کۆی ژمارەکان) و remove(string $name) کە دێڕەکانی ئەو بەرهەمە دەسڕێتەوە. بە ⁦2 × Tea⁩ و ⁦1 × Honey⁩ تاقیی بکەرەوە، پاشان چاکە لاببە.

Hintئاماژە

unset($this->lines[$i]) removes one element of the array inside a foreach ($this->lines as $i => $line).

unset($this->lines[$i]) توخمێکی لە ناو foreach ($this->lines as $i => $line)ـدا لادەبات.

Show answerوەڵامەکە پیشان بدە

Both methods work only on the private $lines, so the rest of the program does not change.

هەردوو تەنیا لەسەر $linesـی private کار دەکەن، بۆیە باقیی بەرنامەکە ناگۆڕێت.

ex_cart_more.phpPHPRuns on the serverلەسەر ڕاژەکاری وێب کار دەکات
<?php
class Product
{
    public function __construct(
        public readonly string $name,
        private int $price,
    ) {}

    public function price(): int
    {
        return $this->price;
    }
}

class Cart
{
    private array $lines = [];

    public function add(Product $product, int $qty = 1): void
    {
        $this->lines[] = ["product" => $product, "qty" => $qty];
    }

    public function count(): int
    {
        $items = 0;
        foreach ($this->lines as $line) {
            $items += $line["qty"];
        }
        return $items;
    }

    public function remove(string $name): void
    {
        foreach ($this->lines as $i => $line) {
            if ($line["product"]->name === $name) {
                unset($this->lines[$i]);
            }
        }
    }

    public function total(): int
    {
        $sum = 0;
        foreach ($this->lines as $line) {
            $sum += $line["product"]->price() * $line["qty"];
        }
        return $sum;
    }
}

$cart = new Cart();
$cart->add(new Product("Tea", 5000), 2);
$cart->add(new Product("Honey", 15000));
echo "Items: ", $cart->count(), ", total: ", number_format($cart->total()), " IQD\n";
$cart->remove("Tea");
echo "Items: ", $cart->count(), ", total: ", number_format($cart->total()), " IQD\n";

Summaryکورتە

  • A class is a plan; new makes objects from it, each with its own property values.
  • -> reaches an object's properties ($tea->price, no $ after the arrow) and methods ($tea->label(), with brackets). Inside a method, $this is the object before the arrow.
  • __construct() runs on every new. Since PHP 8.0, public/private before a constructor parameter declares and fills the property (promotion).
  • Type declarations (int $price) are checked while the script runs; declare(strict_types=1); turns off automatic conversion.
  • public for everyone, private for the class's own code, protected also for child classes. Keep data private and guard it with methods (encapsulation).
  • readonly (8.1): written once, then locked. static members and class constants belong to the class and are reached with :: (self:: inside).
  • Assigning an object copies its handle, not the object; clone makes a copy.
  • Next: build classes on other classes with inheritance, interfaces and traits in Inheritance, Interfaces and Traits. Later, ORM: Working with Tables as Objects turns database rows into objects like these.
  • نەخشەیەکە؛ new لێ دروست دەکات و هەریەکەیان خۆی هەیە.
  • -> دەگاتە ($tea->price، بێ $ لە دوای تیرەکە) و ($tea->label()، بە کەوانەوە). لە ناو ، $this ئەو کە پێش تیرەکەیە.
  • __construct() لە هەموو newـێکدا جێبەجێ دەبێت. لە ⁦PHP 8.0⁩ـەوە، public/private لە پێش دەناسێنێت و پڕی دەکاتەوە ().
  • (int $price) لە کاتی کارکردنی دەپشکنرێن؛ declare(strict_types=1); گۆڕینی خۆکار ڕادەگرێت.
  • public بۆ هەمووان، private بۆ کۆدی خودی ، protected هەروەها بۆ . private بهێڵەوە و بە بیپارێزە ().
  • readonly ⁦(8.1)⁩: یەک جار دەنووسرێت و پاشان قفڵ دەدرێت. و هی و بە :: پێیان دەگەیت (لە ناوەوە self::).
  • یەکسانکردنی دەسکەکەی کۆپی دەکات نەک ؛ clone کۆپییەک دروست دەکات.
  • دواتر: لەسەر تر بنیات بنێ بە ، و لە بۆماوە، نێوبەستەکان و ترەیتەکان. دواتر، ORM: کارکردن لەگەڵ خشتەکان وەک ئۆبجێکتەکان دەکات بە لەم جۆرە.

Lesson complete!وانەکە تەواو بوو!

Well done. Review the key terms, then go on to the next lesson.دەستخۆش. سەیرێکی زاراوە سەرەکییەکان بکەرەوە، پاشان بڕۆ بۆ وانەی داهاتوو.

Key termsزاراوە سەرەکییەکان

Next lessonوانەی داهاتوو

Inheritance, Interfaces and Traitsبۆماوە، نێوبەستەکان و ترەیتەکان

References and further readingسەرچاوەکان و خوێندنەوەی زیاتر

This lecture is a first edition. The Kurdish text and terminology are waiting for review by Kurdish IT teachers.ئەم وانەیە چاپی یەکەمە. دەقە کوردییەکە و زاراوەکانی چاوەڕێی پێداچوونەوەی مامۆستایانی کوردی بواری IT ن.

Appearanceڕووکار

Modeدۆخ
Styleشێواز
Coloursڕەنگەکان

Saved on this device only.تەنیا لەسەر ئەم ئامێرە پاشەکەوت دەکرێت.