面向对象的PHP初学者

原文链接

理解面向对象的编程

面向对象编程是一种编码风格,允许开发人员将类似的任务分组到类中。这有助于保持代码遵循“不要重复自己”(DRY)和易于维护的原则。

“面向对象编程是一种编码风格,允许开发人员将类似的任务分组到类中。”

DRY编程的一个主要好处是,如果程序中的一条信息发生变化,通常只需要进行一次更改即可更新代码。开发人员最大的噩梦之一就是维护代码,一遍又一遍地声明数据,这意味着程序的任何变化都会成为Where's Waldo的一个无比令人沮丧的游戏因为他们寻找重复的数据和功能。

OOP对许多开发人员来说是令人生畏的,因为它引入了新语法,并且一目了然,它似乎比简单的过程代码或内联代码复杂得多。但是,仔细观察后,OOP实际上是一种非常简单且最简单的编程方法。

了解对象和类

在深入了解OOP的细节之前,必须对对象之间的差异有基本的了解。本节将介绍类的构建块,它们的不同功能以及它们的一些用途。

认识到对象和类之间的差异

照片即时杰斐逊约翰·沃德尔

开发人员开始讨论对象和类,它们似乎是可互换的术语。然而,事实并非如此。

马上就有了混乱:经验丰富的开发人员开始讨论对象和类,它们似乎是可互换的术语。然而,事实并非如此,尽管起初差异很大。

例如,一个类就像一个房子的蓝图。它定义了纸房的形状,房屋的不同部分之间的关​​系明确定义和计划,即使房子不存在。

那么,一个物体就像根据那个蓝图建造的实际房屋。存储在物体中的数据就像组成房屋的木头,电线和混凝土:没有根据蓝图组装,它只是一堆东西。然而,当它们汇集在一起​​时,它就变成了一个有组织的,有用的房子。

类构成数据和动作的结构,并使用该信息来构建对象。可以同时从同一个类构建多个对象,每个对象独立于其他对象。继续我们的建筑类比,它类似于整个细分可以从同一个蓝图建立的方式:150个不同的房子,看起来都一样,但
内部有不同的家庭和装饰。

构建类

创建类的语法非常简单:使用class关键字声明一个类,然后是类的名称和一组花括号({}):

1

2

3

4

6

7

8

<?php

 

class MyClass

{

  // Class properties and methods go here

}

 

?>

创建类后,可以使用new关键字实例化一个新类并将其存储在变量中:

1

$obj = new MyClass;

要查看该类的内容,请使用var_dump()

1

var_dump($obj);

通过将所有前面的代码test.php放在[your local] testing文件夹中调用的新文件中来尝试此过程:

01

02

03

04

05

06

07

08

09

10

11

12

<?php

 

class MyClass

{

    // Class properties and methods go here

}

 

$obj = new MyClass;

 

var_dump($obj);

 

?>

在浏览器中加载页面,http://localhost/test.php应显示以下内容:

1

object(MyClass)#1 (0) { }

在最简单的形式中,您刚刚完成了第一个OOP脚本。

定义类属性

要使用向类,属性或类特定变量添加数据。这些工作与常规变量完全相同,除了它们绑定到对象,因此只能使用对象访问。

要添加属性MyClass,请将以下代码添加到脚本中:

01

02

03

04

05

06

07

08

09

10

11

12

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

}

 

$obj = new MyClass;

 

var_dump($obj);

 

?>

关键字public确定属性的可见性,您将在本章后面稍后了解该属性。接下来,使用标准变量语法命名该属性,并指定一个值(尽管类属性不需要初始值)。

要读取此属性并将其输出到浏览器,请引用要读取的对象和要读取的属性:

1

echo $obj->prop1;

因为可以存在类的多个实例,所以如果未引用单个对象,则脚本将无法确定要从哪个对象读取。arrow(->)的使用是一个OOP构造,它访问给定对象的包含属性和方法。

修改脚本test.php以读取属性,而不是通过修改代码来转储整个类,如下所示:

01

02

03

04

05

06

07

08

09

10

11

12

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

}

 

$obj = new MyClass;

 

echo $obj->prop1; // Output the property

 

?>

现在重新加载浏览器会输出以下内容:

1

I'm a class property!

定义类方法

方法是特定于类的函数。对象能够执行的各个动作在类中定义为方法。

例如,要创建设置和获取类属性值的方法$prop1,请将以下内容添加到代码中:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

$obj = new MyClass;

 

echo $obj->prop1;

 

?>

 - OOP允许对象使用引用自己$this。在方法中工作时,使用$this与在类外部使用对象名称相同的方式。

要使用这些方法,请像常规函数一样调用它们,但首先,引用它们所属的对象。阅读该属性MyClass,更改其值,并通过以下修改再次阅读:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

$obj = new MyClass;

 

echo $obj->getProperty(); // Get the property value

 

$obj->setProperty("I'm a new property value!"); // Set a new one

 

echo $obj->getProperty(); // Read it out again to show the change

 

?>

重新加载您的浏览器,您将看到以下内容:

1

2

I'm a class property!

I'm a new property value!

“当使用
同一类的多个实例时,OOP的力量变得明显。”

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

// Create two objects

$obj = new MyClass;

$obj2 = new MyClass;

 

// Get the value of $prop1 from both objects

echo $obj->getProperty();

echo $obj2->getProperty();

 

// Set new values for both objects

$obj->setProperty("I'm a new property value!");

$obj2->setProperty("I belong to the second instance!");

 

// Output both objects' $prop1 value

echo $obj->getProperty();

echo $obj2->getProperty();

 

?>

在浏览器中加载结果时,其内容如下:

1

2

3

4

I'm a class property!

I'm a class property!

I'm a new property value!

I belong to the second instance!

正如您所看到的,OOP将对象保持为单独的实体,这样可以轻松地将不同的代码片段分成小的相关包。

OOP中的魔术方法

为了更容易地使用对象,PHP还提供了许多魔术方法,或在对象中发生某些常见操作时调用的特殊方法。这允许开发人员相对容易地执行许多有用的任务。

使用构造函数和析构函数

当一个对象被实例化时,通常需要立即设置一些东西。为了解决这个问题,PHP提供了魔术方法__construct(),无论何时
创建新对象,都会自动调用该方法。

为了说明构造函数的概念,添加一个构造函数MyClass,只要创建了一个新的类实例,它就会输出一条消息:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

// Create a new object

$obj = new MyClass;

 

// Get the value of $prop1

echo $obj->getProperty();

 

// Output a message at the end of the file

echo "End of file.<br />";

 

?>

 - __CLASS__返回调用它的类的名称; 这就是众所周知的神奇常数。有几个可用的魔术常量,您可以在PHP手册中阅读更多内容。

在浏览器中重新加载文件将产生以下结果:

1

2

3

The class "MyClass" was initiated!

I'm a class property!

End of file.

要在销毁对象时调用函数,可以使用__destruct()魔术方法。这对于类清理很有用(例如,关闭数据库连接)。

通过
__destruct()MyClass以下位置定义魔术方法来销毁对象时输出消息:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

// Create a new object

$obj = new MyClass;

 

// Get the value of $prop1

echo $obj->getProperty();

 

// Output a message at the end of the file

echo "End of file.<br />";

 

?>

定义了析构函数后,重新加载测试文件会产生以下输出:

1

2

3

4

The class "MyClass" was initiated!

I'm a class property!

End of file.

The class "MyClass" was destroyed.

“当达到文件末尾时,PHP会自动释放所有资源。”

要显式触发析构函数,可以使用以下
函数销毁对象unset()

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

// Create a new object

$obj = new MyClass;

 

// Get the value of $prop1

echo $obj->getProperty();

 

// Destroy the object

unset($obj);

 

// Output a message at the end of the file

echo "End of file.<br />";

 

?>

现在,当您在浏览器中加载时,结果将更改为以下内容:

1

2

3

4

The class "MyClass" was initiated!

I'm a class property!

The class "MyClass" was destroyed.

End of file.

转换为字符串

为避免在脚本尝试以MyClass字符串形式输出时出现错误,请使用另一种魔术方法__toString()

没有__toString()尝试将对象输出为字符串会导致致命错误。尝试使用echo输出对象而不使用魔术方法:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

// Create a new object

$obj = new MyClass;

 

// Output the object as a string

echo $obj;

 

// Destroy the object

unset($obj);

 

// Output a message at the end of the file

echo "End of file.<br />";

 

?>

这导致以下结果:

1

2

3

The class "MyClass" was initiated!

 

Catchable fatal error: Object of class MyClass could not be converted to string in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 40

要避免此错误,请添加__toString()方法:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function __toString()

  {

      echo "Using the toString method: ";

      return $this->getProperty();

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

// Create a new object

$obj = new MyClass;

 

// Output the object as a string

echo $obj;

 

// Destroy the object

unset($obj);

 

// Output a message at the end of the file

echo "End of file.<br />";

 

?>

在这种情况下,尝试将对象转换为字符串会导致调用该getProperty()方法。在浏览器中加载测试脚本以查看结果:

1

2

3

4

The class "MyClass" was initiated!

Using the toString method: I'm a class property!

The class "MyClass" was destroyed.

End of file.

提示 - 除了本节中讨论的魔术方法之外,还有其他几种方法可用。有关魔术方法的完整列表,请参阅 PHP手册页

使用类继承

类可以使用extends关键字继承另一个类的方法和属性。例如,要创建扩展MyClass和添加方法的第二个类,您可以将以下内容添加到测试文件中:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function __toString()

  {

      echo "Using the toString method: ";

      return $this->getProperty();

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

class MyOtherClass extends MyClass

{

  public function newMethod()

  {

      echo "From a new method in " . __CLASS__ . ".<br />";

  }

}

 

// Create a new object

$newobj = new MyOtherClass;

 

// Output the object as a string

echo $newobj->newMethod();

 

// Use a method from the parent class

echo $newobj->getProperty();

 

?>

在浏览器中重新加载测试文件后,输出以下内容:

1

2

3

4

The class "MyClass" was initiated!

From a new method in MyOtherClass.

I'm a class property!

The class "MyClass" was destroyed.

覆盖继承的属性和方法

要更改新类中现有属性或方法的行为,可以通过在新类中再次声明它来覆盖它:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function __toString()

  {

      echo "Using the toString method: ";

      return $this->getProperty();

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

class MyOtherClass extends MyClass

{

  public function __construct()

  {

      echo "A new constructor in " . __CLASS__ . ".<br />";

  }

 

  public function newMethod()

  {

      echo "From a new method in " . __CLASS__ . ".<br />";

  }

}

 

// Create a new object

$newobj = new MyOtherClass;

 

// Output the object as a string

echo $newobj->newMethod();

 

// Use a method from the parent class

echo $newobj->getProperty();

 

?>

这会将浏览器中的输出更改为:

1

2

3

4

A new constructor in MyOtherClass.

From a new method in MyOtherClass.

I'm a class property!

The class "MyClass" was destroyed.

覆盖方法时保留原始方法功能

要在保持原始方法完整性的同时向继承的方法添加新功能,请使用parent带有范围分辨率operator::)的关键字:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function __toString()

  {

      echo "Using the toString method: ";

      return $this->getProperty();

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  public function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

class MyOtherClass extends MyClass

{

  public function __construct()

  {

      parent::__construct(); // Call the parent class's constructor

      echo "A new constructor in " . __CLASS__ . ".<br />";

  }

 

  public function newMethod()

  {

      echo "From a new method in " . __CLASS__ . ".<br />";

  }

}

 

// Create a new object

$newobj = new MyOtherClass;

 

// Output the object as a string

echo $newobj->newMethod();

 

// Use a method from the parent class

echo $newobj->getProperty();

 

?>

这将输出父构造函数和新类的构造函数的结果:

1

2

3

4

The class "MyClass" was initiated!

A new constructor in MyOtherClass.

From a new method in MyOtherClass.

I'm a class property!

The class "MyClass" was destroyed.

分配属性和方法的可见性

为了增加对对象的控制,为方法和属性分配可见性。这可以控制如何以及从何处访问属性和方法。有三种可见关键字:publicprotected,和private。除了可见性之外,还可以将方法或属性声明为static,这样就可以在不实例化类的情况下访问它们。

“为了增加对对象的控制,方法和属性被赋予可见性。”

 - 可见性是PHP 5中的一项新功能。有关OOP与PHP 4兼容性的信息,请参阅PHP手册页。

公共属性和方法

到目前为止,您使用的所有方法和属性都是公开的。这意味着它们可以在课堂内和外部访问任何地方。

受保护的属性和方法

声明属性或方法时protected只能在类本身或后代类(扩展包含受保护方法的类的类)中访问它。

getProperty()方法声明为protected in MyClass并尝试直接从类外部访问它:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function __toString()

  {

      echo "Using the toString method: ";

      return $this->getProperty();

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  protected function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

class MyOtherClass extends MyClass

{

  public function __construct()

  {

      parent::__construct();

echo "A new constructor in " . __CLASS__ . ".<br />";

  }

 

  public function newMethod()

  {

      echo "From a new method in " . __CLASS__ . ".<br />";

  }

}

 

// Create a new object

$newobj = new MyOtherClass;

 

// Attempt to call a protected method

echo $newobj->getProperty();

 

?>

尝试运行此脚本时,会显示以下错误:

1

2

3

4

The class "MyClass" was initiated!

A new constructor in MyOtherClass.

 

Fatal error: Call to protected method MyClass::getProperty() from context '' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 55

现在,在MyOtherClass调用getProperty()方法时创建一个新方法:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function __toString()

  {

      echo "Using the toString method: ";

      return $this->getProperty();

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  protected function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

class MyOtherClass extends MyClass

{

  public function __construct()

  {

      parent::__construct();

echo "A new constructor in " . __CLASS__ . ".<br />";

  }

 

  public function newMethod()

  {

      echo "From a new method in " . __CLASS__ . ".<br />";

  }

 

  public function callProtected()

  {

      return $this->getProperty();

  }

}

 

// Create a new object

$newobj = new MyOtherClass;

 

// Call the protected method from within a public method

echo $newobj->callProtected();

 

?>

这会产生所需的结果:

1

2

3

4

The class "MyClass" was initiated!

A new constructor in MyOtherClass.

I'm a class property!

The class "MyClass" was destroyed.

私有属性和方法

声明的属性或方法只能从定义它的类中private访问。这意味着即使新类扩展了定义私有属性的类,该属性或方法也不会在子类中可用。

为了证明这一点,声明getProperty()为私有MyClass,并尝试callProtected()
MyOtherClass以下方面调用:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function __toString()

  {

      echo "Using the toString method: ";

      return $this->getProperty();

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  private function getProperty()

  {

      return $this->prop1 . "<br />";

  }

}

 

class MyOtherClass extends MyClass

{

  public function __construct()

  {

      parent::__construct();

      echo "A new constructor in " . __CLASS__ . ".<br />";

  }

 

  public function newMethod()

  {

      echo "From a new method in " . __CLASS__ . ".<br />";

  }

 

  public function callProtected()

  {

      return $this->getProperty();

  }

}

 

// Create a new object

$newobj = new MyOtherClass;

 

// Use a method from the parent class

echo $newobj->callProtected();

 

?>

重新加载浏览器,出现以下错误:

1

2

3

4

The class "MyClass" was initiated!

A new constructor in MyOtherClass.

 

Fatal error: Call to private method MyClass::getProperty() from context 'MyOtherClass' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 49

静态属性和方法

声明的方法或属性static可以在不首先实例化类的情况下访问; 您只需提供类名,范围解析运算符以及属性或方法名称。

“使用静态属性的一个主要好处是它们在脚本的持续时间内保留它们的存储值。”

为了演示这一点,添加一个名为的静态属性$count和一个名为plusOne()to 的静态方法MyClass。然后设置一个do...while循环以输出递增的值,$count只要该值小于10:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

<?php

 

class MyClass

{

  public $prop1 = "I'm a class property!";

 

  public static $count = 0;

 

  public function __construct()

  {

      echo 'The class "', __CLASS__, '" was initiated!<br />';

  }

 

  public function __destruct()

  {

      echo 'The class "', __CLASS__, '" was destroyed.<br />';

  }

 

  public function __toString()

  {

      echo "Using the toString method: ";

      return $this->getProperty();

  }

 

  public function setProperty($newval)

  {

      $this->prop1 = $newval;

  }

 

  private function getProperty()

  {

      return $this->prop1 . "<br />";

  }

 

  public static function plusOne()

  {

      return "The count is " . ++self::$count . ".<br />";

  }

}

 

class MyOtherClass extends MyClass

{

  public function __construct()

  {

      parent::__construct();

      echo "A new constructor in " . __CLASS__ . ".<br />";

  }

 

  public function newMethod()

  {

      echo "From a new method in " . __CLASS__ . ".<br />";

  }

 

  public function callProtected()

  {

      return $this->getProperty();

  }

}

 

do

{

  // Call plusOne without instantiating MyClass

  echo MyClass::plusOne();

} while ( MyClass::$count < 10 );

 

?>

 - 访问静态属性时,美元符号
$位于范围解析运算符之后。

在浏览器中加载此脚本时,将输出以下内容:

01

02

03

04

05

06

07

08

09

10

The count is 1.

The count is 2.

The count is 3.

The count is 4.

The count is 5.

The count is 6.

The count is 7.

The count is 8.

The count is 9.

The count is 10.

评论DocBlocks

“DocBlock评论风格是一种广泛
接受的记录类的方法。”

虽然不是OOP的官方部分,但DocBlock评论风格是一种广泛接受的记录类的方法。除了为
开发人员在编写代码时提供标准外,它还被许多最流行的软件开发工具包(SDK)采用,例如EclipseNetBeans,并将用于生成代码提示。

通过使用以附加星号开头的块注释来定义DocBlock:

1

2

3

/**

 * This is a very basic DocBlock

 */

DocBlocks的真正强大之处在于能够使用标签标签以符号(@)后面紧跟标签名称和标签值开头。DocBlock标签允许开发人员定义文件的作者,类的许可,属性或方法信息以及其他有用信息。

使用的最常见标签如下:

  • @author:使用此标记列出当前元素的作者(可能是类,文件,方法或任何代码)。如果记入多个作者,则可以在同一DocBlock中使用多个作者标签。作者姓名的格式是John Doe <[email protected]>
  • @copyright:这表示当前元素的版权所有者的版权年份和名称。格式是2010 Copyright Holder
  • @license:这链接到当前元素的许可证。许可证信息的格式是
    http://www.example.com/path/to/license.txt License Name
  • @var:它包含变量或类属性的类型和描述。格式是type element description
  • @param:此标记显示函数或方法参数的类型和描述。格式是type $element_name element description
  • @return:此标记中提供了函数或方法的返回值的类型和描述。格式是type return element description

使用DocBlocks评论的示例类可能如下所示:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

<?php

 

/**

 * A simple class

 *

 * This is the long description for this class,

 * which can span as many lines as needed. It is

 * not required, whereas the short description is

 * necessary.

 *

 * It can also span multiple paragraphs if the

 * description merits that much verbiage.

 *

 * @author Jason Lengstorf <[email protected]>

 * @copyright 2010 Ennui Design

 * @license http://www.php.net/license/3_01.txt PHP License 3.01

 */

class SimpleClass

{

  /**

   * A public variable

   *

   * @var string stores data for the class

   */

  public $foo;

 

  /**

   * Sets $foo to a new value upon class instantiation

   *

   * @param string $val a value required for the class

   * @return void

   */

  public function __construct($val)

  {

      $this->foo = $val;

  }

 

  /**

   * Multiplies two integers

   *

   * Accepts a pair of integers and returns the

   * product of the two.

   *

   * @param int $bat a number to be multiplied

   * @param int $baz a number to be multiplied

   * @return int the product of the two parameters

   */

  public function bar($bat, $baz)

  {

      return $bat * $baz;

  }

}

 

?>

一旦你扫描了上面的类,DocBlock的好处是显而易见的:一切都是明确定义的,以便下一个开发人员可以获取代码,而不必想知道代码片段的作用或应该包含的内容。

比较面向对象和程序代码

编写代码并不是一种正确和错误的方法。话虽如此,本节概述了在软件开发中采用面向对象方法的强有力论据,特别是在大型应用程序中。

原因1:易于实施

“虽然起初可能令人生畏,但OOP实际上提供了一种更简单的数据处理方法。”

虽然起初可能令人生畏,但OOP实际上提供了一种更简单的数据处理方法。因为对象可以在内部存储数据,所以不需要将变量从函数传递到函数以正常工作。

此外,由于同一类的多个实例可以同时存在,因此处理大型数据集非常容易。例如,假设您在文件中处理了两个人的信息。他们需要姓名,职业和年龄。

程序方法

以下是我们示例的程序方法:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

<?php

 

function changeJob($person, $newjob)

{

  $person['job'] = $newjob; // Change the person's job

  return $person;

}

 

function happyBirthday($person)

{

  ++$person['age']; // Add 1 to the person's age

  return $person;

}

 

$person1 = array(

  'name' => 'Tom',

  'job' => 'Button-Pusher',

  'age' => 34

);

 

$person2 = array(

  'name' => 'John',

  'job' => 'Lever-Puller',

  'age' => 41

);

 

// Output the starting values for the people

echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";

echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";

 

// Tom got a promotion and had a birthday

$person1 = changeJob($person1, 'Box-Mover');

$person1 = happyBirthday($person1);

 

// John just had a birthday

$person2 = happyBirthday($person2);

 

// Output the new values for the people

echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";

echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";

 

?>

执行时,代码输出以下内容:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

Person 1: Array

(

  [name] => Tom

  [job] => Button-Pusher

  [age] => 34

)

Person 2: Array

(

  [name] => John

  [job] => Lever-Puller

  [age] => 41

)

Person 1: Array

(

  [name] => Tom

  [job] => Box-Mover

  [age] => 35

)

Person 2: Array

(

  [name] => John

  [job] => Lever-Puller

  [age] => 42

)

虽然这段代码不一定是坏的,但在编码时要记住很多。必须传递受影响人的属性数组并从每个函数调用返回,这会留下误差。

为了清理这个例子,我们希望尽可能少留给开发人员。只需要将当前操作的绝对必要信息传递给函数。

这是OOP介入的地方,可以帮助您清理。

OOP方法

以下是我们示例的OOP方法:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

<?php

 

class Person

{

  private $_name;

  private $_job;

  private $_age;

 

  public function __construct($name, $job, $age)

  {

      $this->_name = $name;

      $this->_job = $job;

      $this->_age = $age;

  }

 

  public function changeJob($newjob)

  {

      $this->_job = $newjob;

  }

 

  public function happyBirthday()

  {

      ++$this->_age;

  }

}

 

// Create two new people

$person1 = new Person("Tom", "Button-Pusher", 34);

$person2 = new Person("John", "Lever Puller", 41);

 

// Output their starting point

echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";

echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";

 

// Give Tom a promotion and a birthday

$person1->changeJob("Box-Mover");

$person1->happyBirthday();

 

// John just gets a year older

$person2->happyBirthday();

 

// Output the ending values

echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";

echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";

 

?>

这将在浏览器中输出以下内容:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

Person 1: Person Object

(

  [_name:private] => Tom

  [_job:private] => Button-Pusher

  [_age:private] => 34

)

 

Person 2: Person Object

(

  [_name:private] => John

  [_job:private] => Lever Puller

  [_age:private] => 41

)

 

Person 1: Person Object

(

  [_name:private] => Tom

  [_job:private] => Box-Mover

  [_age:private] => 35

)

 

Person 2: Person Object

(

  [_name:private] => John

  [_job:private] => Lever Puller

  [_age:private] => 42

)

为了使方法面向对象,需要更多的设置,但是在定义了类之后,创建和修改人员变得轻而易举; 一个人的信息不需要从方法传递或返回,只有绝对必要的信息传递给每个方法。

“如果实施得当,OOP将大大减少您的工作量。”

在小规模上,这种差异可能看起来不多,但随着应用程序规模的扩大,如果正确实施,OOP将显着减少您的工作量。

提示 - 并非所有内容都需要面向对象。在应用程序内的一个地方处理小事的快速函数不一定需要包含在类中。在决定面向对象和程序方法时,请使用您的最佳判断。

原因2:更好的组织

OOP的另一个好处是它有助于轻松打包和编目。每个类通常可以保存在自己的单独文件中,如果使用统一的命名约定,访问类非常简单。

假设您有一个包含150个类的应用程序,这些类通过应用程序文件系统根目录下的控制器文件动态调用。所有150个类都遵循命名约定class.classname.inc.php并驻留在inc应用程序的文件夹中。

控制器可以实现PHP的__autoload()功能,只在动态调入所需的类,而不是将所有150包含在控制器文件中,以防万一或想出一些巧妙的方法将文件包含在你自己的代码中:

1

2

3

4

6

<?php

  function __autoload($class_name)

  {

      include_once 'inc/class.' . $class_name . '.inc.php';

  }

?>

将每个类放在一个单独的文件中也可以使代码更加便携,并且更容易在新应用程序中重用,而无需进行大量复制和粘贴。

原因3:维护更方便

由于正确完成OOP的更紧凑性,代码的更改通常比长意大利面条代码程序实现更容易发现和制作。

如果特定信息数组获得新属性,则程序性软件可能需要(在最坏的情况下)将新属性添加到使用该数组的每个函数中。

OOP应用程序可能会更新为轻松添加新属性,然后添加处理所述属性的方法。

本节涉及的许多好处是OOP与DRY编程实践相结合的产物绝对有可能创建易于维护的过程代码,不会导致恶梦,并且同样可能创建可怕的面向对象的代码。[ Pro PHP和jQuery ]将尝试与OOP一起演示良好编码习惯的组合,以生成易于阅读和维护的简洁代码。

猜你喜欢

转载自blog.csdn.net/kevlin_V/article/details/83869621