Hướng dẫn php use - sử dụng php

Xin chào tất cả mọi người. Hôm nay mình sẽ quay lại phần 2 trong bài viết về lập trình hướng đối tượng trong PHP. Trong phần 1 mình sẽ đề cập về ba vấn đề Các đặc điểm cơ bản của lập trình hướng đối tượng. Chúng được thể hiện như thế nào trong PHP, Sự khác biệt giữa Abstract Class và Interface và Thế nào là một hàm static, phân biệt cách dùng từ khoá static::method() với self::method().Các đặc điểm cơ bản của lập trình hướng đối tượng. Chúng được thể hiện như thế nào trong PHP, Sự khác biệt giữa Abstract Class và InterfaceThế nào là một hàm static, phân biệt cách dùng từ khoá static::method() với self::method().

Mục lục

Phần 1

  • Các đặc điểm cơ bản của lập trình hướng đối tượng. Chúng được thể hiện như thế nào trong PHP
  • Sự khác biệt giữa Abstract Class và Interface.
  • Thế nào là một hàm static. Phân biệt cách dùng từ khoá static::method() với self::method()

Phần 2

  • Thế nào là Trait
  • Thế nào là Namespaces
  • Thế nào là magic functions
  • Tìm hiểu về các quy tắc trong PSR-2

Phần 3

  • Các phương pháp thiết kế hướng đối tượng (SOLID)

Trong phần này, mình sẽ chia sẻ về 4 vấn tiếp theo trong loạt bài viết, đó là: Thế nào là Trait, Thế nào là Namespaces, Thế nào là magic functions, Tìm hiểu về các quy tắc trong PSR2.Thế nào là Trait, Thế nào là Namespaces, Thế nào là magic functions, Tìm hiểu về các quy tắc trong PSR2.

Nội dung

4. Thế nào là Trait

Trait được giới thiệu trong PHP phiên bản 5.4.0 và được định nghĩa là một cơ chế cho phép lập trình viên tận dụng khả năng tái sử dụng lại code (code reusability) khi lập trình với ngôn ngữ chỉ cho phép thừa kế từ một class duy nhất (hay còn gọi là single inheritance) như PHP. Vậy


trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

2 là gì? Trait là một module giúp cho chúng ta có thể sử dụng lại các phương thức được khai báo trong trait vào các class khác nhau hoặc trong các trait khác một cách đơn giản hơn là kế thừa như trước. Một trait tương tự như là 1 class nhưng chỉ nhằm mục đích nhóm chức năng lại. Và trait không thể khởi tạo giống class và trait sinh ra để bổ sung cho kế thừa truyền thống. Thay vì phải kế thừa 1 class hay interface để sử dụng lại 1 nhóm chức năng, thì với trait bạn không cần phải kế thừa vẫn có thể sử dụng được. Ví dụ:trait tương tự như là 1 class nhưng chỉ nhằm mục đích nhóm chức năng lại. Và trait không thể khởi tạo giống class và trait sinh ra để bổ sung cho kế thừa truyền thống. Thay vì phải kế thừa 1 class hay interface để sử dụng lại 1 nhóm chức năng, thì với trait bạn không cần phải kế thừa vẫn có thể sử dụng được. Ví dụ:


class Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Report extends Database
{
	
	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Users extends Database
{
	public function index()
	{
		$this->listUsers();
	}	
}

Đây là trường hợp không sử dụng


trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

3 và cũng không biết dùng trait ở đâu

Hướng dẫn php use - sử dụng php

. Mà ta thấy nếu có nếu có quá nhiều class thì việc extends lại sẽ làm ảnh hưởng rất nhiều đến công việc, tài nguyên, hiệu năng. Hướng giải quyết như sau:

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

Các bạn thấy không, mình không cần extends nhưng vẫn có thể sử dụng lại các phương thức của method listUsers() như trên. Để sử dụng trait trong PHP thì các bạn chỉ cần dùng từ khóa use để gọi trait bạn muốn sử dụng trong code của bạn. Sau đó bạn có thể sử dụng các phương thức trong trait mà bạn đã


trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

4. Ví dụ ở trên mình

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

4 Database sau đó sẽ sử dụng lại được phương thức listUser() trong trait này À, đến đây, ta lại thấy, nếu muốn sử dụng nhiều phương thức trong nhiều trait thì làm như thế nào? Tiếp tục nhé.listUsers() như trên. Để sử dụng trait trong PHP thì các bạn chỉ cần dùng từ khóa use để gọi trait bạn muốn sử dụng trong code của bạn. Sau đó bạn có thể sử dụng các phương thức trong trait mà bạn đã

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

4. Ví dụ ở trên mình

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

4 Database sau đó sẽ sử dụng lại được phương thức listUser() trong trait này À, đến đây, ta lại thấy, nếu muốn sử dụng nhiều phương thức trong nhiều trait thì làm như thế nào? Tiếp tục nhé.


trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!

Các bạn hãy nhìn hình nhé. Ở đây mình có 2 trait là Hello và World chứa lần lượt phương thức là sayHello() và sayWorld(). Và việc sử dụng chúng rất đơn giản như là sử dụng một


trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

3 vậy. Bạn có thể

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

4 và sử dụng các phương thức bên trong nó như bình thường. Có vẻ mọi thứ đã ổn. Nhưng nếu một ngày không đẹp trời, các phương thức trong các

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

3 giống nhau, chúng ta sẽ phải làm sao? Ở đây ta sẽ sử dụng

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

9 để xét độ ưu tiên cho phương thức bạn muốn sử dụng. Ví dụ :sayHello()sayWorld(). Và việc sử dụng chúng rất đơn giản như là sử dụng một

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

3 vậy. Bạn có thể

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

4 và sử dụng các phương thức bên trong nó như bình thường. Có vẻ mọi thứ đã ổn. Nhưng nếu một ngày không đẹp trời, các phương thức trong các

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

3 giống nhau, chúng ta sẽ phải làm sao? Ở đây ta sẽ sử dụng

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

9 để xét độ ưu tiên cho phương thức bạn muốn sử dụng. Ví dụ :


//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}

Tiếp theo, chúng ta sẽ tìm hiểu về 1 phần rất quan trọng trong


trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

3 đó là

trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

3 lồng. Bạn đã bao giờ nghĩ nếu có 100 trait, ta sẽ use tận 100 lần. Điều này là không nên. Nhìn rất củ chuối =))) Ví dụ:


trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!

Việc sử dụng


trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

3 lồng không quá phức tạp và là cách giúp cho code dễ nhìn, hiệu quả hơn.

5. Thế nào là namespace

  • Khái niệm: Theo php.net thì nó là cách để đóng gói những file php. Được thiết kế để giải quyết 2 vấn đề là thể hiện được tác quyền của thư viện đang sử dụng và sự đụng độ không gian tên trên những ứng dụng khi tạo ra những thành phần code tái sử dụng như các classes hay functions.php.net thì nó là cách để đóng gói những file php. Được thiết kế để giải quyết 2 vấn đề là thể hiện được tác quyền của thư viện đang sử dụng và sự đụng độ không gian tên trên những ứng dụng khi tạo ra những thành phần code tái sử dụng như các classes hay functions.

  • Định nghĩa: Được khai báo với từ khóa

    
    trait Database
    {
      public function sayHello()
      {
      	echo "hello";
      }
    }
    /**
    * 
    */
    trait World
    {
      public function sayWorld()
      {
      	echo "World";
      }
    }
    /**
    * 
    */
    class MyHelloWorld
    {
      use Database, World;
    
      public function sayHelloWorld() {
      	echo "!";
      }
    }
    
    $o = new MyHelloWorld();
    $o->sayHello();
    $o->sayWorld();
    $o->sayHelloWorld();
    //Kết quả : helloWorld!
    
    3. Mỗi file chứa 1 namespace phải được khai báo trên cùng trước các code khác trong file. Cách thực hành tốt nhất là mỗi file chứa 1 class với tên class trùng với tên file đồng thời có 1 namespace mô tả được đường dẫn tới file đó

  • Khai báo : Giống như đường dẫn tới thư mục. Cách thực hành tốt nhất là nên đặt namespaces theo cấu trúc thư mục chứa nó, điều này là tuyệt vời khi kết hợp với autoloading trong PHP. VD: Tạo 1 class HomeController và đặt tên như sau:

    namespace App\Controllers; 
    
    class HomeController {
      //code
    }
    

    Sử dụng name space:

    use App\Controllers\HomeController;
    

6. Thế nào là magic functions

Trong lập trình hướng đối tượng để làm cho việc sử dụng các đối tượng dễ dàng hơn, PHP cũng cung cấp một số Magic Method, hoặc các phương thức đặc biệt được gọi khi các hành động nhất định xảy ra trong các đối tượng. Điều này cho phép các lập trình viên thực hiện một số nhiệm vụ hữu ích tương đối dễ dàng. Trong bài này mình xin phép nói về 2 magic function quan trọng và hay dùng nhất trong lập trình hướng đối tượng trong PHP. Đó là


trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
4 và

trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
5. Trước hết mình xin đi vào

trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
4, vậy

trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
4 là gì? Xét ví dụ sau:lập trình hướng đối tượng để làm cho việc sử dụng các đối tượng dễ dàng hơn, PHP cũng cung cấp một số Magic Method, hoặc các phương thức đặc biệt được gọi khi các hành động nhất định xảy ra trong các đối tượng. Điều này cho phép các lập trình viên thực hiện một số nhiệm vụ hữu ích tương đối dễ dàng. Trong bài này mình xin phép nói về 2 magic function quan trọng và hay dùng nhất trong lập trình hướng đối tượng trong PHP. Đó là

trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
4 và

trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
5. Trước hết mình xin đi vào

trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
4, vậy

trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
4 là gì? Xét ví dụ sau:


/**
* 
*/
class ClassName
{
    public $example = "Đây là thuộc tính của class";
	
    public function __construct()
	{
		echo "Đối tượng vừa được khởi tạo! 
"
; } public function setProperty($value) { $this->example = $value; } public function getProperty() { return $this->example . '
'
; } } $obj = new ClassName(); echo $obj->getProperty(); // kết quả : //Đối tượng vừa được khởi tạo! //Đây là thuộc tính của class

Các bạn thấy gì nào? Sau khi khởi tạo đối tượng NameClass, lập tức hàm


trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
8 sẽ tự động chạy. Điều này giống như một cách thông báo đến người lập trình.

trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
5: Bản chất ngược lại với

trait Database
{
  public function sayHello()
  {
  	echo "hello";
  }
}
/**
* 
*/
trait World
{
  public function sayWorld()
  {
  	echo "World";
  }
}
/**
* 
*/
class MyHelloWorld
{
  use Database, World;

  public function sayHelloWorld() {
  	echo "!";
  }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayHelloWorld();
//Kết quả : helloWorld!
4. Ví dụ:


/**
* 
*/
class ClassName
{
    public $example = "Đây là thuộc tính của class";
	
    public function __construct()
	{
		echo "Đối tượng vừa được khởi tạo! 
"
; } public function setProperty($value) { $this->example = $value; } public function getProperty() { return $this->example . '
'
; } public function __destruct() { echo "Đối tượng vừa bị hủy!
"
; } } $obj = new ClassName(); echo $obj->getProperty(); echo "Kết thúc! "; //kết quả: //Đối tượng vừa được khởi tạo! //Đây là thuộc tính của class //Kết thúc! Đối tượng vừa bị hủy!

Để kích hoạt destructor một cách rõ ràng, bạn có thể hủy đối tượng Object ngay lập tức bằng cách sử dụng hàm


//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
1 :


/**
* 
*/
class ClassName
{
    public $example = "Đây là thuộc tính của class";
	
    public function __construct()
	{
		echo "Đối tượng vừa được khởi tạo! 
"
; } public function setProperty($value) { $this->example = $value; } public function getProperty() { return $this->example . '
'
; } public function __destruct() { echo "Đối tượng vừa bị hủy!
"
; } } $obj = new ClassName(); echo $obj->getProperty(); unset($obj); echo "Kết thúc! "; //kết quả: //Đối tượng vừa được khởi tạo! //Đây là thuộc tính của class //Đối tượng vừa bị hủy! //Kết thúc!

Tiếp theo, chúng ta sẽ đi đến các hàm quan trọng khác...


//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
2 : sẽ tự động được gọi khi chúng ta lấy ra giá trị của các thuộc tính trong đối mà chúng ta không được phép truy cập nó từ bên ngoài hoặc không tồn tại. VD:


trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

0


//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
3 : sẽ tự động được gọi khi chúng ta thiết lập giá trị cho một thuộc tính không được phép truy cập từ bên ngoài, hoặc không tồn tại.


trait Database
{
	public function listUsers()
	{
		return "List User";
	}
}
/**
* 
*/
class Users
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}
/**
* 
*/
class Report
{
	use Database;

	public function reportUsers()
	{
		$this->listUsers();
	}
}

1

Ngoài ra còn một số magic funtions dưới đây mình xin phép được liệt kê dưới đây:


//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
4 : hàm isset, sẽ được gọi khi chúng ta thực hiện kiểm tra một thuộc tính không được phép truy cập của một đối tượng, hay kiểm tra một thuộc tính không tồn tại trong đối tượng đó.

//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
5: sẽ được gọi khi chúng ta thực hiện hủy (unset) một thuộc tính không được phép truy cập của một đối tượng, hay hủy một thuộc tính không tồn tại trong đối tượng đó. Cụ thể là hàm unset().

//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
6 : Phương thức

//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
6 sẽ được gọi khi chúng ta thực hiện

//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
8đối tượng. Thông thường khi chúng ta

//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
8một đối tượng thì nó sẽ trả về tất cả các thuộc tính trong đối tượng đó. Nhưng nếu sử dụng

//trait SetGetName
trait SetGetName
{
   public function setName($name)
   {
   	$this->name = $name;
   }
   public function getName()
   {
   	return $this->name;
   }
   public function getAll()
   {
   	return $this->getName();
   }
   
}
//trait SetGetAge
trait SetGetAge
{
   public function setAge($age)
   {
   	$this->age = $age;
   }
   public function getAge()
   {
   	return $this->age;
   }
   public function getAll()
   {
   	return $this->getAge();
   }
}
class ConNguoi
{
   public $name;
   private $age;
   //gọi trait
   use SetGetName,SetGetAge
   {
   	//ưu tiên sử dụng phương thức getall của trait SetGetAge
   	SetGetAge::getAll insteadof SetGetName;
   }
}
6 thì chúng ta có thể quy định được các thuộc tính có thể trả về.

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!
1: sẽ được gọi khi chúng ta unserialize() đối tượng. Chúng thường được sử dụng để thực thi một hoặc nhiều hành động nào đó khi đối tượng được unserialize().

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!
2: sẽ được gọi khi chúng ta dùng đối tượng như một string.

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!
3: sẽ được gọi khi chúng ta sử đối tượng như một hàm.

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!
4: Đây là phương thức ít được sử dụng nhất trong PHP và hầu như là không bao giờ. Phương thức này sẽ được gọi khi chúng ta var_export() đối tượng.

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!
5: được gọi khi chúng ta clone object.

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!
6: được gọi khi chúng ta

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!
7 đối tượng. Thông thường, khi chúng ta

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!
7 một đối tượng thì nó sẽ trả về tất cả các thuộc tính và giá trị của nó trong đối tượng đó, nhưng khi chúng ta sử dụng phương thức

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
// kết quả : Hello World!
6thì chúng ta có thể tùy chỉnh thông số trả về.
namespace App\Controllers; 

class HomeController {
  //code
}
0: hàm call, được gọi khi ta gọi đến một phương thức không tồn tại trong đối tượng
namespace App\Controllers; 

class HomeController {
  //code
}
1: hàm call static, được gọi khi ta gọi đến một phương thức tĩnh không tồn tại trong đối tượng

Ưu và nhược điểm của magic functions :magic functions :

  • Ưu điểm:
    • Giúp cho chúng ta tùy biến được các hành vi.
    • Nó giúp cho chúng ta có thể khởi tạo một đối tượng theo cách mình muốn.
  • Nhược điểm:
    • Tốc độ chậm hơn các function bình thường.

7. Các quy tắc trong PSR-2

Viết code chuẩn (coding convention) là chúng ta tuân thủ một quy định trong viết code của một tập thể hay một công ty dựa theo quy chuẩn trong lập trình. Tùy thuộc vào ngôn ngữ sẽ có chuẩn viết code khác nhau. Trong bài viết này mình sẽ nói về chuẩn code PSR-2 trong PHP.

PSR có nghĩa là PHP Standards Recommendations. Có rất nhiều PSR từ PSR-0 đến PSR-7. Trong đó PSR-1 và PSR-2 chúng ta sẽ tiếp xúc rất nhiều. PSR-1 sẽ giúp chúng ta biết thề nào và làm thế nào để đặt tên biến, tên hàm sau cho dể hiểu, dể đọc mang tính thống nhất toàn bộ.

Khác với PSR-1, PSR-2 sẽ mang tính trình bày là chính. Nó có nhiệm vụ rất quan trong trong việc trình bài các dòng code của bạn. từ các dòng tab hay xuống hàng giữa các dòng, các hàm một cách tỉ mỉ.

Vậy tại sao lại phải viết code chuẩn

  • Như mình đã đề cập ở trên việc viết code chuẩn rất quan trọng. đối với những ai thường không tuân theo quy định viết code chuẩn (viết tùy ý) đó chỉ có thể làm việc cá nhân.
  • Các bạn nên nhớ rằng khi đi làm chúng ta điều làm teamwork không thể mõi người một cách viết. Mõi người một cách viết là đúng khi nói về tư duy logic trong lập trình có thể cùng một kết quả nhưng lại có nhiều cách viết khác nhau.
  • Sự thống nhất về cách trình bày. Bạn viết như thế nào khi người khác xem lại hoặc sữa code của bạn vẫn hiểu được cái function của bạn đang viết cái gì phải không nào.

Các quy tắc::

  • Code PHẢI tuân thủ PSR-1
  • Code PHẢI sử dụng 4 ký tự space để lùi khối (không dùng tab)
  • Mỗi dòng code PHẢI dưới 120 ký tự, NÊN dưới 80 ký tự.
  • PHẢI có 1 dòng trắng sau namespace, và PHẢI có một dòng trắng sau mỗi khối code.
  • Ký tự mở lớp { PHẢI ở dòng tiếp theo, và đóng lớp } PHẢI ở dòng tiếp theo của thân class.
  • Ký tự { cho hàm PHẢI ở dòng tiếp theo, và ký tự } kết thúc hàm PHẢI ở dòng tiếp theo của thân hàm.
  • Các visibility (public, private, protected) PHẢI được khai báo cho tất cả các hàm và các thuộc tính của lớp;
  • Các từ khóa điều khiển khối(if, elseif, else) PHẢI có một khoảng trống sau chúng; hàm và lớp thì KHÔNG ĐƯỢC làm như vậy.
  • Mở khối { cho cấu trúc điều khiển PHẢI trên cùng một dòng; và đóng khối này với } ở dòng tiếp theo của thân khối.
  • Hằng số true, false, null PHẢI viết với chữ thường.
  • Từ khóa extends và implements PHẢI cùng dòng với class
  • Implements nhiều lớp, thì mỗi lớp trên một dòng
  • Keyword var KHÔNG ĐƯỢC dùng sử dụng khai báo property.
  • Tên property KHÔNG NÊN có tiền tố _ nhằm thể hiện thuộc tính protect hay private.
  • Tham số cho hàm, phương thức: KHÔNG được thêm space vào trước dấu , và PHẢI có một space sau ,. Các tham số CÓ THỂ trên nhiều dòng, nếu làm như vậy thì PHẢI mỗi dòng 1 tham số.
  • Abstract, final PHẢI đứng trước visibility, còn static phải đi sau.

Một số chi tiết về chuẩn PSR-1:

  • Các file phải sử dụng thẻ
    namespace App\Controllers; 
    
    class HomeController {
      //code
    }
    
    2 hoặc
    namespace App\Controllers; 
    
    class HomeController {
      //code
    }
    
    3.
  • File PHP chỉ sử dụng encode: UTF-8 without BOM với code PHP.
  • Các file nên dùng để khai báo các thành phần PHP (các lớp, hàm, hằng ...) hoặc dùng với mục đích làm hiệu ứng phụ (như include, thiết lập ini cho PHP ...), nhưng không nên dùng trong cả 2 trường hợp.
  • Các
    
    trait Database
    {
      public function sayHello()
      {
      	echo "hello";
      }
    }
    /**
    * 
    */
    trait World
    {
      public function sayWorld()
      {
      	echo "World";
      }
    }
    /**
    * 
    */
    class MyHelloWorld
    {
      use Database, World;
    
      public function sayHelloWorld() {
      	echo "!";
      }
    }
    
    $o = new MyHelloWorld();
    $o->sayHello();
    $o->sayWorld();
    $o->sayHelloWorld();
    //Kết quả : helloWorld!
    
    3 và các
    namespace App\Controllers; 
    
    class HomeController {
      //code
    }
    
    5 phải theo chuẩn "autoloading" PSR: [PSR-0 và PSR-4].
  • Tên Class phải có dạng NameClass.
  • Hằng số trong class phải được khai báo bằng cách viết hoa và chia ra bởi dấu
    namespace App\Controllers; 
    
    class HomeController {
      //code
    }
    
    6.
  • Tên của phương thức phải được khai báo theo kiểu
    namespace App\Controllers; 
    
    class HomeController {
      //code
    }
    
    7, Ví dụ :
    namespace App\Controllers; 
    
    class HomeController {
      //code
    }
    
    8,
    namespace App\Controllers; 
    
    class HomeController {
      //code
    }
    
    9... Tham Khảo thêm tại PSR và Coding Standard in Framgia để có thể xem thêm nhiều thông tin chi tiết về vấn đề này.

Tạm kết

Đến đây, mình xin tạm dừng bài viết về Lập trình hướng đối tượng trong PHP tại đây. Cảm ơn các bạn đã theo dõi. Qua phần 1 và phần 2 này. Hi vọng các bạn đã có một cái nhìn rõ ràng hơn về lập trình hướng đối tượng. Trong phần cuối, mình sẽ viết về các phương pháp thiết kế hướng đối tượng (SOLID). Mong được sự theo dõi và ủng hộ từ các bạn. Xem thêm phần 1 và Phần 3.các phương pháp thiết kế hướng đối tượng (SOLID). Mong được sự theo dõi và ủng hộ từ các bạn. Xem thêm phần 1 và Phần 3.