所以基本上我是从过程编码到面向对象的飞跃。我试图实现面向对象的原则,但我有一种唠叨的感觉,我实际上只是在用对象编写过程风格。
假设我有一个管道/椅子/打印机/任何东西的列表,它们都被列为我的单表数据库中的产品。我需要建立一个web应用程序,显示整个列表和项目取决于他们的类型,重点是"正确"使用OOP和它的范式。
这样做有什么不对吗:
CLass Show { public function showALL(){ $prep = "SELECT * FROM myProducts"; $q = $this->db-> prepare($prep); $q->execute(); while ($row = $q->fetch()) { echo "bla bla bla some arranged display".$row['something'] } }
和
$sth = new show();
$sth->showAll();
我还将实现更具体的显示方法,如:
showSpecificProduct($id)->($id将通过$_GET传递当用户点击其中一个链接时我们将有一个单独的product。php文件基本上只包含
include('show.class.php');
$sth = new show();
$sth->showSpecificProduct($id);
showSpecificProduct()将做选择查询和输出html显示。
简短地说,我是在做这个还是在用类和对象做过程性编码。如果我做错了,还有什么想法/提示等解决它吗?
与@Phil和@Drew描述的模型实践一样,我建议您将业务层、数据层和视图层分开。
我已经包含了一个非常简单的版本,需要在你的实现中扩展,但这个想法是保持你的Db选择与你的输出分开,几乎在控制器中将两者"连接"在一起。
class ProductController
{
public $view;
public function __construct() {
$this->view = new View;
}
public function indexAction() {
$model = new DbProductRepository;
$products = $model->fetchAll();
$this->view->products = $products;
$this->view->render('index', 'product');
}
}
class View
{
protected $_variables = array();
public function __get($name) {
return isset($this->_variables['get']) ? $this->_variables['get'] : null;
}
public function __set($name, $value) {
$this->_variables[$name] = $value;
}
public function render($action, $controller) {
require_once '/path/to/views/' . $controller . '/' . $action . '.php';
}
}
// in /path/to/views/product/index.php
foreach ($this->products as $product) {
echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />n";
}
更合适的方法是实现存储库模式。一个示例接口可能是
interface ProductRepository
{
public function find($id);
public function fetchAll();
}
然后创建该接口的具体实现
class DbProductRepository implements ProductRepsoitory
{
private $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function find($id)
{
// prepare execute SQL statement
// Fetch result
// return result
}
public function fetchAll()
{
// etc
}
}
直接从方法或函数中获取echo
通常是一个坏主意。让您的方法返回适当的对象/数组/任何东西,并使用这些结果。
你上面描述的场景似乎是MVC的一个很好的候选。
在您的情况下,我会创建一个严格用于访问数据的类(做产品类别或特定产品的选择),然后有一个不同的文件(您的视图)接受输出并显示它。
可以是这样的:
class Product_Model {
public function find($prodId) { ... }
public function fetchAll($category = '') { ... }
public function search($string) { ... }
}
那么你可以在其他地方做:
$products = new Product_Model();
$list = $products->fetchAll(37); // get all from category 37
// in true MVC, you would have a view that you would assign the list to
// $view->list = $list;
foreach($ilst as $product) {
echo "Product ID {$product['id']} - {$product['name']} - {$product['cost']}<br />n";
}
MVC的基本原则是你有模型类,这些模型类是简单的对象,表示来自某些数据源(例如数据库)的数据。您可能有一个映射器,将数据从数据库映射到数据对象。然后,控制器将从模型类中获取数据,并将信息发送到视图,在视图中处理实际的表示。在控制器中使用视图逻辑(html/javascript)是不可取的,直接与控制器中的数据交互也是一样的。
首先,您需要了解类的自动加载。这样你就不需要包含你使用的每个类,你只需要使用它,自动加载器就会为你找到合适的文件。
http://php.net/manual/en/language.oop5.autoload.php每个类应该有一个单独的职责。您不会有一个类连接到数据库,并更改一些用户数据。相反,您将拥有一个数据库类,并将其传递给用户类,而用户类将使用该数据库类访问数据库。每个函数也应该有一个单独的职责。你不应该急于在函数名中加上"and"。
你不希望一个对象知道另一个对象的属性。这将导致在一个类中进行更改,从而迫使您在另一个类中进行更改,并最终使更改变得困难。属性只能在对象内部使用。
在您开始编写一个类之前,您应该首先考虑您希望如何使用它(参见测试驱动开发)。在使用它时,您希望代码看起来如何?
$user = new User($db_object);
$user->load($id);
$user->setName($new_name);
$user->save();
既然你知道你想如何使用它,那么用正确的方式来编码它就容易多了。
当你有机会的时候,研究一下敏捷原则。
一个经验法则是类名通常应该是名词,因为OOP是关于拥有对应于真实概念对象的软件对象。类成员函数通常是动词,即可以对对象执行的操作。
在你的例子中,show是一个奇怪的类名。一种更典型的方法是使用一个名为ProductViewer之类的类,并带有一个名为show()或list()的成员函数。此外,您还可以使用子类来获得专门的功能,例如针对特定产品类型的自定义视图。