English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
في تصميم البرمجيات المتجهة نحو الكائنات (باللغة الإنجليزية: Object-oriented programming، اختصار: OOP)، الكائن هو كيان يتكون من معلومات ووصف كيفية معالجة هذه المعلومات، وهو تعبير عن العالم الحقيقي.
في العالم الحقيقي، كل شيء نواجهه هناك كائنات، مثل الحواسيب، التلفزيونات، الدراجات، وما إلى ذلك.
ثلاث خصائص رئيسية للاعبين:
سلوك الكائن: يمكن تطبيق هذه العمليات على الكائن، تشغيل الضوء، إطفاء الضوء هي سلوكيات.
شكل الكائن: كيف يستجيب الكائن عند تطبيق هذه الطرق، اللون، الحجم، الشكل.
تمثيل الكائن: تمثيل الكائن يشبه بطاقة الهوية، والفرق بينها في ما هو مختلف في نفس السلوك والحالة.
مثلاً Animal(حيوان) هو فئة抽象ة، يمكننا أن نكون محددين في كلب وغنم، وكلب وغنم هما كائنان محددان، لديهما خصائص اللون، يمكن كتابتها، يمكنها الحركة، وما إلى ذلك من الحالات والسلوكيات.
الفئة − يحدد السمات التجريدية لأمر ما. تتضمن تعريف الفئة شكل البيانات ومعاملات البيانات.
الكائن − هو مثال على الفئة.
متغير العضو − يتم تعريفها داخل الفئة، ويُمكن استخدامها لاستقبال قيم متغيرات العضويات. يمكن تسمية هذا المتغير بعد إنشاء الكائن كخاصية للكائن.
وظيفة العضو − يتم تعريفها داخل الفئة، ويُمكن استخدامها لاستقبال بيانات الكائن.
继承 − هو آلية تمكن الكائن الفرعي من مشاركة بنية البيانات وعمليات الكائن الأب، وهي علاقة بين الفئات. يمكن تعريف وتنفيذ فئة عند بناء على فئة موجودة مسبقًا، حيث يتم أخذ محتويات الفئة الموجودة مسبقًا كمحتويات خاصة، وإضافة بعض المحتويات الجديدة.
الكائن الأب − يُسمى الكائن الذي يتم ترقيته من قبل كائن آخر كائن آب أو كائن أساسي أو كائن فوق.
الكائن الفرعي − يُسمى الكائن الذي يرث من كائن آخر كائن فرعي، أو كائن ناتج عن التوليد.
التعددية − يُعرف التعددية بأنها قدرة نفس الوظيفة أو الطريقة على العمل على أنواع مختلفة من الكائنات للحصول على نتائج مختلفة. يمكن أن تتولد نتائج مختلفة عند استقبال نفس الرسالة من كائنات مختلفة، ويُسمى هذا الظاهرة تعددية.
التحميل − يمكن ببساطة القول إنه عندما تكون هناك نفس الأسماء للوظائف أو الطرق ولكن قوائم الأ参数 مختلفة، فإن هذه الوظائف أو الطرق التي لها نفس الأسماء ولكن قوائم الأ参数 المختلفة تُسمى الوظائف أو الطرق الم负担的 أو المبالغ فيها.
الاستنتاج − يُعرف الاستنتاج بأنه تحويل الكائنات التي تحتوي على بنية بيانات متطابقة (الخصائص) وسلوكيات متطابقة (العمليات) إلى فئات. الفئة هي هذا النوع من الاستنتاج، والتي تعكس الخصائص المهمة المتعلقة بتطبيق، وتتجاهل بعض المعلومات غير ذات الصلة. يجب أن تكون أي قسمة للفئات موضوعية، ولكن يجب أن تكون مرتبطة بتطبيق محدد.
التجميع − التجميع هو ربط خصائص الكائن والسلوكيات التي توجد في العالم الحقيقي معًا، ووضعها في وحدة منطقية.
构造函数 − يتم استخدامها بشكل رئيسي لتحديد بداية الكائن، أي إعداد قيم متغيرات العضويات للكائن، وتُستخدم دائمًا مع عمليات new في جملة إنشاء الكائن.
析构函数 − الوظيفة المدمجة (destructor) هي العكس من الوظيفة المكونة، حيث يتم تنفيذ الوظيفة المدمجة تلقائيًا عند انتهاء حياة الكائن (مثل انتهاء عمل الدالة التي يحتوي عليها الكائن). غالبًا ما يتم استخدام الوظيفة المدمجة لعمل "التنظيف النهائي" (مثل استخدام new لإنشاء مساحة ذاكرة عند إنشاء الكائن، يجب استخدام delete لتحريرها قبل الخروج).
في الصورة أدناه، قمنا بإنشاء ثلاثة أجهزة باستخدام فئة Car: Mercedes، Bmw، وأudi.
$mercedes = new Car(); $bmw = new Car(); $audi = new Car();
PHP 定义类通常语法格式如下:
<?php class phpClass { var $var1; var $var2 = "constant string"; function myfunc ($arg1, $arg2) { [..] } [..] } ؟
解析如下:
类使用 class 关键字后加上类名定义。
类名后的一对大括号({})内可以定义变量和方法。
类的变量使用 var 来声明, 变量也可以初始化值。
函数定义类似 PHP 函数的定义,但函数只能通过该类及其示例化的对象访问。
<?php class Site { /* 成员变量 */ var $url; var $title; /* 成员函数 */ function setUrl($par){ $this->url = $par; } function getUrl(){ echo $this->url . PHP_EOL; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title . PHP_EOL; } } ؟
变量 $this 代表自身的对象。
PHP_EOL 为换行符。
类创建后,我们可以使用 new 运算符来示例化该类的对象:
$w3codebox = new Site; $taobao = new Site; $google = new Site;
以上代码我们创建了三个对象,三个对象各自都是独立的,接下来我们来看看如何访问成员方法与成员变量。
在示例化对象后,我们可以使用该对象调用成员方法,该对象的成员方法只能操作该对象的成员变量:
// 调用成员函数,设置标题和URL $w3codebox->setTitle( "基础教程网" ); $taobao->setTitle( "淘宝" ); $google->setTitle( "Google 搜索" ); $w3codebox->setUrl( 'ar.oldtoolbag.com' ); $taobao->setUrl( 'www.taobao.com' ); $google->setUrl( 'www.google.com' ); // Call member functions to get title and URL $w3codebox->getTitle(); $taobao->getTitle(); $google->getTitle(); $w3codebox->getUrl(); $taobao->getUrl(); $google->getUrl();
完整代码如下:
<?php class Site { /* 成员变量 */ var $url; var $title; /* 成员函数 */ function setUrl($par){ $this->url = $par; } function getUrl(){ echo $this->url . PHP_EOL; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title . PHP_EOL; } } $w3codebox = new Site; $taobao = new Site; $google = new Site; // 调用成员函数,设置标题和URL $w3codebox->setTitle( "基础教程网" ); $taobao->setTitle( "天猫商城" ); $google->setTitle( "Google 搜索" ); $w3codebox->setUrl( 'ar.oldtoolbag.com' ); $taobao->setUrl( 'www.tmall.com' ); $google->setUrl( 'www.google.com' ); // Call member functions to get title and URL $w3codebox->getTitle(); $taobao->getTitle(); $google->getTitle(); $w3codebox->getUrl(); $taobao->getUrl(); $google->getUrl(); ؟
عند تنفيذ الكود أعلاه، الناتج المطلوب هو:
基础教程网 天猫商城 Google 搜索 ar.oldtoolbag.com www.tmall.com www.google.com
The constructor is a special method. It is mainly used to initialize an object when creating an object, that is, to assign initial values to the object member variables, and it is used together with the new operator in the statement of creating an object.
PHP 5 allows developers to define a method as a constructor within a class, and the syntax format is as follows:
void __construct ([ mixed $args [, $... ]]]
In the above example, we can initialize the $url and $title variables through the constructor method:
function __construct( $par1, $par2 ) { $this->url = $par1; $this->title = $par2; }
Now we no longer need to call the setTitle and setUrl methods:
$w3codebox = new Site('ar.oldtoolbag.com', '基础教程网'); $tmall = new Site('www.tmall.com', '天猫商城'); $google = new Site('www.google.com', 'Google 搜索'); // Call member functions to get title and URL $w3codebox->getTitle(); $tmall->getTitle(); $google->getTitle(); $w3codebox->getUrl(); $tmall->getUrl(); $google->getUrl();
The destructor (destructor) is the opposite of the constructor, and it is automatically executed by the system when an object ends its life cycle (for example, when the function in which the object is located has been called).
PHP 5 introduces the concept of a destructor, which is similar to other object-oriented languages, and its syntax format is as follows:
void __destruct ( void )
<?php class MyDestructableClass { function __construct() { print "构造函数\n"; $this->name = "MyDestructableClass"; } function __destruct() { print "销毁 " . $this->name . "\n"; } } $obj = new MyDestructableClass(); ؟
عند تنفيذ الكود أعلاه، الناتج المطلوب هو:
构造函数 销毁 MyDestructableClass
PHP 使用关键字 extends 来继承一个类,PHP 不支持多继承,格式如下:
class Child extends Parent { // 代码部分 }
示例中 Child_Site 类继承了 Site 类,并扩展了功能:
<?php // 子类扩展站点类别 class Child_Site extends Site { var $category; function setCate($par){ $this->category = $par; } function getCate(){ echo $this->category . PHP_EOL; } }
如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
示例中重写了 getUrl 与 getTitle 方法:
function getUrl() { echo $this->url . PHP_EOL; return $this->url; } function getTitle(){ echo $this->title . PHP_EOL; return $this->title; }
PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有)、protected(受保护)或 private(私有)来实现的。
public(公有):公有的类成员可以在任何地方被访问。
protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
private(私有):私有的类成员只能被其定义所在的类访问。
类的属性必须定义为公有、受保护、私有之一。如果使用 var 定义,则被视为公有。
<?php /** * تعريف MyClass */ class MyClass { public $public = 'Public'; protected $protected = 'Protected'; private $private = 'Private'; function printHello() { echo $this->public; echo $this->protected; echo $this->private; } } $obj = new MyClass(); echo $obj->public; // يمكن تنفيذ هذا بشكل طبيعي echo $obj->protected; // هذا سينتج عنه خطأ فادح echo $obj->private; // هذا سينتج عنه خطأ فادح $obj->printHello(); // يُطبع Public، Protected و Private /** * تعريف MyClass2 */ class MyClass2 extends MyClass { // يمكن تعريف public و protected، لكن private لا يمكن protected $protected = 'Protected2'; function printHello() { echo $this->public; echo $this->protected; echo $this->private; } } $obj2 = new MyClass2(); echo $obj2->public; // يمكن تنفيذ هذا بشكل طبيعي echo $obj2->private; // غير معرف private echo $obj2->protected; // هذا سينتج عنه خطأ فادح $obj2->printHello(); // يُطبع Public، Protected2 و Undefined ؟
يمكن تعريف طرق الكائن في MyClass كعام أو خاص أو مدمج. إذا لم يتم تعيين هذه الكلمات المفتاحية، فإن الطريقة تكون عامة افتراضًا.
<?php /** * تعريف MyClass */ class MyClass { // إعلان بناء عام public function __construct() { } // إعلان طريقة عامة public function MyPublic() { } // إعلان طريقة مدمجة protected function MyProtected() { } // إعلان طريقة خاصة private function MyPrivate() { } // هذه الطريقة هي عامة function Foo() { $this->MyPublic(); $this->MyProtected(); $this->MyPrivate(); } } $myclass = new MyClass; $myclass->MyPublic(); // يمكن تنفيذ هذا بشكل طبيعي $myclass->MyProtected(); // هذا سينتج عنه خطأ فادح $myclass->MyPrivate(); // هذا سينتج عنه خطأ فادح $myclass->Foo(); // يمكن تنفيذ العامة والمدعومة والخاصة /** * تعريف MyClass2 */ class MyClass2 extends MyClass { // هذه الطريقة هي عامة function Foo2() { $this->MyPublic(); $this->MyProtected(); $this->MyPrivate(); // هذا السطر سيؤدي إلى إصدار خطأ حاد } } $myclass2 = new MyClass2; $myclass2->MyPublic(); // يمكن تنفيذ هذا السطر بشكل طبيعي $myclass2->Foo2(); // يمكن تنفيذ العامة والمدعومة، ولكن غير المدعومة لا يمكن تنفيذها class Bar { public function test() { $this->testPrivate(); $this->testPublic(); } public function testPublic() { echo "Bar::testPublic\n"; } private function testPrivate() { echo "Bar::testPrivate\n"; } } class Foo extends Bar { public function testPublic() { echo "Foo::testPublic\n"; } private function testPrivate() { echo "Foo::testPrivate\n"; } } $myFoo = new foo(); $myFoo->test(); // Bar::testPrivate // Foo::testPublic ؟
باستخدام واجهة (interface)، يمكنك تحديد ما يجب تنفيذه من الطرق من قبل فئة معينة، دون الحاجة إلى تعريف محتوى هذه الطرق.
تتمثل الواجهة في interface كلمات المفتاحية لتعريفها، مثل تعريف فئة معيارية، ولكن جميع الطرق المحددة تكون فارغة.
جميع الطرق المحددة في الواجهة يجب أن تكون عامة، وهي خاصية الواجهة.
لتنفيذ واجهة، استخدم implements لا بد من تنفيذ جميع الطرق المحددة في واجهة، وإلا سيتم إصدار خطأ حاد. يمكن للفئة تنفيذ واجهات متعددة، باستخدام الفاصلة للفصل بين أسماء الواجهات.
<?php // تصريح واجهة 'iTemplate' interface iTemplate { public function setVariable($name, $var); public function getHtml($template); } // تنفيذ واجهة class Template implements iTemplate { private $vars = array(); public function setVariable($name, $var) { $this->vars[$name] = $var; } public function getHtml($template) { foreach($this->vars as $name => $value) { $template = str_replace('{'. $name .'}', $value, $template); } return $template; } }
يمكن تعريف القيم التي تبقى ثابتة في الفئة كمعادلة ثابتة. عند تعريف واستخدام المعادلة الثابتة، لا يجب استخدام رمز $.
يجب أن تكون قيمة الدالة دالة ثابتة، وليس متغيرًا، أو خاصية فئة، أو نتيجة حساب رياضي أو استدعاء دالة.
بدءًا من PHP 5.3.0، يمكن استخدام متغير لتحويل ديناميكي للفئات. ولكن يجب ألا يكون قيمة المتغير كلمة مفتاحية (مثل self،parent أو static).
<?php class MyClass { const constant = 'قيمة الدالة'; function showConstant() { echo self::constant . PHP_EOL; } } echo MyClass::constant . PHP_EOL; $classname = "MyClass"; echo $classname::constant . PHP_EOL; // بدءًا من 5.3.0 $class = new MyClass(); $class->showConstant(); echo $class::constant . PHP_EOL; // بدءًا من PHP 5.3.0 ؟
أي فئة، إذا كان لديها على الأقل طريقة معلن عنها كم抽象ة، فإنها يجب أن تكون معلن عنها كفئة م抽象ة.
لا يمكن إنشاء امثلة للفئات الم抽象ة.
الطرق الم抽象ة المحددة تعلن فقط طريقة الت 호출 (المستويات)، ولا يمكن تعريف تنفيذها المحدد.
عندما يتم استنساخ فئة م抽象ة، يجب على الفئة الفرعية تعريف جميع الطرق الم抽象ة في الفئة الأم؛ بالإضافة إلى ذلك، يجب أن تكون سيطرة الوصول على هذه الطرق متطابقة مع الفئة الأم (أو أكثر حرية). على سبيل المثال، إذا تم إعلان طريقة م抽象ة كمعتمدة، فإن الطريقة المطبقة في الفئة الفرعية يجب أن تكون معتمدة أو عامة، وليس خاصة.
<?php abstract class AbstractClass { // ُيتطلب من الفئة الفرعية تعريف هذه الطرق abstract protected function getValue(); abstract protected function prefixValue($prefix); // ُطريقة عادية (ليست طريقة تجريدية) public function printOut() { print $this->getValue() . PHP_EOL; } } class ConcreteClass1 extends AbstractClass { protected function getValue() { return "ConcreteClass1"; } public function prefixValue($prefix) { return "{$prefix}ConcreteClass1"; } } class ConcreteClass2 extends AbstractClass { public function getValue() { return "ConcreteClass2"; } public function prefixValue($prefix) { return "{$prefix}ConcreteClass2"; } } $class1 = new ConcreteClass1; $class1->printOut(); echo $class1->prefixValue('FOO_') . PHP_EOL; $class2 = new ConcreteClass2; $class2->printOut(); echo $class2->prefixValue('FOO_') . PHP_EOL; ؟
عند تنفيذ الكود أعلاه، الناتج المطلوب هو:
ConcreteClass1 FOO_ConcreteClass1 ConcreteClass2 FOO_ConcreteClass2
بالإضافة إلى ذلك، يمكن للطريقة الفرعية أن تحتوي على معلمات اختيارية غير موجودة في الطريقة التجريدية للفئة الأب.
على سبيل المثال، يمكن للفئة الفرعية تعريف معلمة اختيارية ليست موجودة في إعلان الطريقة التجريدية للفئة الأب، ولكن يمكن تشغيلها بشكل طبيعي.
<?php abstract class AbstractClass { // ُنحن نحتاج إلى تعريف المعلمات المطلوبة فقط في طريقتنا التجريدية abstract protected function prefixName($name); } class ConcreteClass extends AbstractClass { // يمكن لفرعيتنا تعريف معاملات إضافية غير موجودة في توقيع الصنف الأب public function prefixName($name, $separator = ".") { if ($name == "Pacman") { $prefix = "Mr"; } elseif ($name == "Pacwoman") { $prefix = "Mrs"; } else { $prefix = ""; } return "{$prefix}{$separator} {$name}"; } } $class = new ConcreteClass; echo $class->prefixName("Pacman"), "\n"; echo $class->prefixName("Pacwoman"), "\n"; ؟
نتيجة الإخراج هي:
Mr. Pacman Mrs. Pacwoman
بإعلان الصفة أو الطريقة كـ static (رياضية)، يمكن الوصول إليها مباشرة دون تصنيع الفئة.
لا يمكن الوصول إلى الصفات الرياضية من خلال كائن تم تصنيعه من الفئة (لكن يمكن الوصول إلى الطرق الرياضية).
بما أن الطرق الرياضية لا تحتاج إلى كائن للإتصال بها، فإن المتغير الوهمي $this غير متاح في الطرق الرياضية.
لا يمكن للصفات الرياضية أن يتم الوصول إليها من خلال الكائن باستخدام عمودية ->.
من PHP 5.3.0، يمكن استخدام متغير لتحويل ديناميكي للفئة. ولكن لا يمكن أن يكون قيمة المتغير كلمة مفتاحية self، parent أو static.
<?php class Foo { public static $my_static = 'foo'; public function staticValue() { return self::$my_static; } } print Foo::$my_static . PHP_EOL; $foo = new Foo(); print $foo->staticValue() . PHP_EOL; ؟
باستخدام برنامج أعلاه، النتيجة الخارجة ستكون:
foo foo
PHP 5 إضافة كلمة مفتاحية final. إذا تم إعلان طريقة في الصنف الأب كـ final، فإن الصنف الفرعي لا يمكنه تغطية هذه الطريقة. إذا تم إعلان الصنف كـ final، فإنه لا يمكن توريثه.
استخدام الكود التالي سيؤدي إلى ظهور خطأ:
<?php class BaseClass { public function test() { echo "BaseClass::test() called" . PHP_EOL; } final public function moreTesting() { echo "BaseClass::moreTesting() called" . PHP_EOL; } } class ChildClass extends BaseClass { public function moreTesting() { echo "ChildClass::moreTesting() called" . PHP_EOL; } } // رسالة خطأ كومية: Cannot override final method BaseClass::moreTesting() ؟
PHP لن يدعو تلقائيًا طريقة بناء الفئة الأصلية في طريقة بناء الفئة الفرعية. لإجراء طريقة بناء الفئة الأصلية، يجب استدعاءها في طريقة بناء الفئة الفرعية parent::__construct() .
<?php class BaseClass { function __construct() { print "طريقة بناء الكلاس BaseClass" . PHP_EOL; } } class SubClass extends BaseClass { function __construct() { parent::__construct(); // لا يمكن للفئة الفرعية استدعاء طريقة بناء الفئة الأصلية تلقائيًا print "طريقة بناء الكلاس SubClass" . PHP_EOL; } } class OtherSubClass extends BaseClass { // تنسيق طريقة بناء الكلاس BaseClass } // استدعاء طريقة بناء الكلاس BaseClass $obj = new BaseClass(); // استدعاء طريقة بناء الكلاس BaseClass و SubClass $obj = new SubClass(); // استدعاء طريقة بناء الكلاس BaseClass $obj = new OtherSubClass(); ؟
باستخدام برنامج أعلاه، النتيجة الخارجة ستكون:
طريقة بناء الكلاس BaseClass طريقة بناء الكلاس BaseClass طريقة بناء الكلاس SubClass طريقة بناء الكلاس BaseClass