Php:学习OOP,静态与常规方法
这是我在堆栈溢出中的第一篇帖子,如果我不遵守任何规则,请容忍我。我用php编写脚本已经有一段时间了,但实际上从未使用过它的OOP端。我一直在网上做一个培训课程(不确定我是否大声说出是哪一个是因为版权?) 无论哪种方式,在程序员在他的一个类中创建了一些静态方法的过程中,我决定我不想让我的方法成为静态的。下面是他写的代码。我做了同样的事情,只是对代码中的变量引用不同,比如$this->variablePhp:学习OOP,静态与常规方法,php,class,oop,object,methods,Php,Class,Oop,Object,Methods,这是我在堆栈溢出中的第一篇帖子,如果我不遵守任何规则,请容忍我。我用php编写脚本已经有一段时间了,但实际上从未使用过它的OOP端。我一直在网上做一个培训课程(不确定我是否大声说出是哪一个是因为版权?) 无论哪种方式,在程序员在他的一个类中创建了一些静态方法的过程中,我决定我不想让我的方法成为静态的。下面是他写的代码。我做了同样的事情,只是对代码中的变量引用不同,比如$this->variable `<?php // If it's going to need the database,
`<?php
// If it's going to need the database, then it's
// probably smart to require it before we start.
require_once(LIB_PATH.DS.'database.php');
class Photograph extends DatabaseObject {
protected static $table_name="photographs";
protected static $db_fields=array('id', 'filename', 'type', 'size', 'caption');
public $id;
public $filename;
public $type;
public $size;
public $caption;
private $temp_path;
protected $upload_dir="images";
public $errors=array();
protected $upload_errors = array(
// http://www.php.net/manual/en/features.file-upload.errors.php
UPLOAD_ERR_OK => "No errors.",
UPLOAD_ERR_INI_SIZE => "Larger than upload_max_filesize.",
UPLOAD_ERR_FORM_SIZE => "Larger than form MAX_FILE_SIZE.",
UPLOAD_ERR_PARTIAL => "Partial upload.",
UPLOAD_ERR_NO_FILE => "No file.",
UPLOAD_ERR_NO_TMP_DIR => "No temporary directory.",
UPLOAD_ERR_CANT_WRITE => "Can't write to disk.",
UPLOAD_ERR_EXTENSION => "File upload stopped by extension."
);
// Pass in $_FILE(['uploaded_file']) as an argument
public function attach_file($file) {
// Perform error checking on the form parameters
if(!$file || empty($file) || !is_array($file)) {
// error: nothing uploaded or wrong argument usage
$this->errors[] = "No file was uploaded.";
return false;
} elseif($file['error'] != 0) {
// error: report what PHP says went wrong
$this->errors[] = $this->upload_errors[$file['error']];
return false;
} else {
// Set object attributes to the form parameters.
$this->temp_path = $file['tmp_name'];
$this->filename = basename($file['name']);
$this->type = $file['type'];
$this->size = $file['size'];
// Don't worry about saving anything to the database yet.
return true;
}
}
public function save() {
// A new record won't have an id yet.
if(isset($this->id)) {
// Really just to update the caption
$this->update();
} else {
// Make sure there are no errors
// Can't save if there are pre-existing errors
if(!empty($this->errors)) { return false; }
// Make sure the caption is not too long for the DB
if(strlen($this->caption) > 255) {
$this->errors[] = "The caption can only be 255 characters long.";
return false;
}
// Can't save without filename and temp location
if(empty($this->filename) || empty($this->temp_path)) {
$this->errors[] = "The file location was not available.";
return false;
}
// Determine the target_path
$target_path = SITE_ROOT .DS. 'public' .DS. $this->upload_dir .DS. $this->filename;
// Make sure a file doesn't already exist in the target location
if(file_exists($target_path)) {
$this->errors[] = "The file {$this->filename} already exists.";
return false;
}
// Attempt to move the file
if(move_uploaded_file($this->temp_path, $target_path)) {
// Success
// Save a corresponding entry to the database
if($this->create()) {
// We are done with temp_path, the file isn't there anymore
unset($this->temp_path);
return true;
}
} else {
// File was not moved.
$this->errors[] = "The file upload failed, possibly due to incorrect permissions on the upload folder.";
return false;
}
}
}
public function destroy() {
// First remove the database entry
if($this->delete()) {
// then remove the file
// Note that even though the database entry is gone, this object
// is still around (which lets us use $this->image_path()).
$target_path = SITE_ROOT.DS.'public'.DS.$this->image_path();
return unlink($target_path) ? true : false;
} else {
// database delete failed
return false;
}
}
public function image_path() {
return $this->upload_dir.DS.$this->filename;
}
public function size_as_text() {
if($this->size < 1024) {
return "{$this->size} bytes";
} elseif($this->size < 1048576) {
$size_kb = round($this->size/1024);
return "{$size_kb} KB";
} else {
$size_mb = round($this->size/1048576, 1);
return "{$size_mb} MB";
}
}
// Common Database Methods
public static function find_all() {
return self::find_by_sql("SELECT * FROM ".self::$table_name);
}
public static function find_by_id($id=0) {
global $database;
$result_array = self::find_by_sql("SELECT * FROM ".self::$table_name." WHERE id=".$database->escape_value($id)." LIMIT 1");
return !empty($result_array) ? array_shift($result_array) : false;
}
public static function find_by_sql($sql="") {
global $database;
$result_set = $database->query($sql);
$object_array = array();
while ($row = $database->fetch_array($result_set)) {
$object_array[] = self::instantiate($row);
}
return $object_array;
}
private static function instantiate($record) {
// Could check that $record exists and is an array
$object = new self;
// Simple, long-form approach:
// $object->id = $record['id'];
// $object->username = $record['username'];
// $object->password = $record['password'];
// $object->first_name = $record['first_name'];
// $object->last_name = $record['last_name'];
// More dynamic, short-form approach:
foreach($record as $attribute=>$value){
if($object->has_attribute($attribute)) {
$object->$attribute = $value;
}
}
return $object;
}
private function has_attribute($attribute) {
// We don't care about the value, we just want to know if the key exists
// Will return true or false
return array_key_exists($attribute, $this->attributes());
}
protected function attributes() {
// return an array of attribute names and their values
$attributes = array();
foreach(self::$db_fields as $field) {
if(property_exists($this, $field)) {
$attributes[$field] = $this->$field;
}
}
return $attributes;
}
protected function sanitized_attributes() {
global $database;
$clean_attributes = array();
// sanitize the values before submitting
// Note: does not alter the actual value of each attribute
foreach($this->attributes() as $key => $value){
$clean_attributes[$key] = $database->escape_value($value);
}
return $clean_attributes;
}
// replaced with a custom save()
// public function save() {
// // A new record won't have an id yet.
// return isset($this->id) ? $this->update() : $this->create();
// }
public function create() {
global $database;
// Don't forget your SQL syntax and good habits:
// - INSERT INTO table (key, key) VALUES ('value', 'value')
// - single-quotes around all values
// - escape all values to prevent SQL injection
$attributes = $this->sanitized_attributes();
$sql = "INSERT INTO ".self::$table_name." (";
$sql .= join(", ", array_keys($attributes));
$sql .= ") VALUES ('";
$sql .= join("', '", array_values($attributes));
$sql .= "')";
if($database->query($sql)) {
$this->id = $database->insert_id();
return true;
} else {
return false;
}
}
public function update() {
global $database;
// Don't forget your SQL syntax and good habits:
// - UPDATE table SET key='value', key='value' WHERE condition
// - single-quotes around all values
// - escape all values to prevent SQL injection
$attributes = $this->sanitized_attributes();
$attribute_pairs = array();
foreach($attributes as $key => $value) {
$attribute_pairs[] = "{$key}='{$value}'";
}
$sql = "UPDATE ".self::$table_name." SET ";
$sql .= join(", ", $attribute_pairs);
$sql .= " WHERE id=". $database->escape_value($this->id);
$database->query($sql);
return ($database->affected_rows() == 1) ? true : false;
}
public function delete() {
global $database;
// Don't forget your SQL syntax and good habits:
// - DELETE FROM table WHERE condition LIMIT 1
// - escape all values to prevent SQL injection
// - use LIMIT 1
$sql = "DELETE FROM ".self::$table_name;
$sql .= " WHERE id=". $database->escape_value($this->id);
$sql .= " LIMIT 1";
$database->query($sql);
return ($database->affected_rows() == 1) ? true : false;
// NB: After deleting, the instance of User still
// exists, even though the database entry does not.
// This can be useful, as in:
// echo $user->first_name . " was deleted";
// but, for example, we can't call $user->update()
// after calling $user->delete().
}
}
?>`
当我做同样的事情,但与一个对象的照片实例
$photo_object = new Photograph();
$photos = find_all();
如果我试着和他做同样的循环,我只会一次又一次地得到相同的结果(目前数据库中有4个条目,我得到了大约10次完全相同的条目)
这是我的代码,它产生了这个输出
<?php require_once("../../includes/initialize.php"); ?>
<?php if(!$session->is_logged_in()) { redirect_to("login.php");} ?>
<?php
//This is the class being called
$photo_object = new Photograph();
//Find all photos will return the result from the database. We then need to call the fetch array onit
//$photos = $photo_object->find_all_photos();
$photos = $photo_object->find_all();
?>
<?php include_layout_template('admin_header.php'); ?>
<h2>Photographs: List</h2>
<?php echo output_message($message);?>
<table class="bordered">
<tr>
<th>Image</th>
<th>Filename</th>
<th>Caption</th>
<th>Size</th>
<th>Type</th>
<th> </th>
</tr>
<?php foreach($photos as $photo): ?>
<tr>
<td><img src="<?php echo "../" . $photo_object->image_path() . $photo_object->filename;?>" width="100" /></td>
<td><?php echo $photo_object->filename; ?></td>
<td><?php echo $photo_object->caption; ?></td>
<td><?php echo $photo_object->size_as_text($photo_object->size); ?></td>
<td><?php echo $photo_object->type ?></td>
<td><a href="delete_photo.php?id=<?php echo $photo_object->id;?>">Delete</a> </td>
</tr>
<?php endforeach; ?>
</table>
<br />
<a href="photo_upload.php">Upload a new photograph</a>
<?php include_layout_template('admin_footer.php'); ?>
这是可行的,但我不使用类中的任何变量,而是调用我在foreach循环(foreach($photos as$photo))中创建的photo数组。这使得类中的属性看起来毫无意义。我这样做对了吗?还是有什么东西我只是不了解的对象
提前谢谢你对我的帮助
快乐编码现在的代码将
$object\u数组
传递到实例化
但是,instantiate
被构建为只接受从结果集检索到的一行
如果在传递它之前检查$object\u array
,您将了解获得不希望的结果的更多原因
public function find_by_sql($sql="") {
global $database;
$result = $database->query($sql);
$object_array = $database->fetch_array($result);
// Examine $object_array:
print '<pre>';
var_dump($object_array);
print '</pre>';
$object = $this->instantiate($object_array);
return $object_array;
}
我建议取消对它们的注释,并检查$row
:
private function instantiate($record) {
//Could check if $record exists and is an array
//Simple long form approach
//$object = new self;
$this->id= $record['id'];
$this->filename = $record['filename'];
$this->type = $record['type'];
$this->size = $record['size'];
$this->caption = $record['caption'];
}
这是一个开始,让你了解为什么你会看到10倍相同的结果
我写了一个例子来说明你将如何去做你想要做的事情(从你的评论中决定):
或者当您想使用您的线路时:
您可以这样做:
我希望这能为您澄清一些问题。您现在拥有的代码将
$object\u array
传递到实例化中
但是,instantiate
被构建为只接受从结果集检索到的一行
如果在传递它之前检查$object\u array
,您将了解获得不希望的结果的更多原因
public function find_by_sql($sql="") {
global $database;
$result = $database->query($sql);
$object_array = $database->fetch_array($result);
// Examine $object_array:
print '<pre>';
var_dump($object_array);
print '</pre>';
$object = $this->instantiate($object_array);
return $object_array;
}
我建议取消对它们的注释,并检查$row
:
private function instantiate($record) {
//Could check if $record exists and is an array
//Simple long form approach
//$object = new self;
$this->id= $record['id'];
$this->filename = $record['filename'];
$this->type = $record['type'];
$this->size = $record['size'];
$this->caption = $record['caption'];
}
这是一个开始,让你了解为什么你会看到10倍相同的结果
我写了一个例子来说明你将如何去做你想要做的事情(从你的评论中决定):
或者当您想使用您的线路时:
您可以这样做:
我希望这能为您澄清一些问题。您的函数“find_all”函数是否位于Photograph类中?当您想在像find_all()这样的对象中调用函数时,必须指定objectinstance:$photo_object->find_all();很抱歉是的,我的全部都找到了。确实住在摄影班里,我在我的帖子里犯了一个错误。我本来打算把$photos=$photo\u object->find\u all()放在上面,而不是=find\u all()。它仍然不起作用,我只是一遍又一遍地从数据库中得到相同的结果。这就好像类中的变量在循环发生时不发生变化。在我看来,这就像ActiveRecord。您没有使用这些属性,因为您正在实现和讨论静态的存储库方法。我猜在收到一个对象后,您可以修改它,然后保存它,然后执行相对SQL。这是一个ORM的原始实现。好的,很好!:)你能展示你得到的输出,并解释你想要的输出是什么,它们之间的区别是什么吗?对。我已将代码改回在photo类中使用标准的find_all()。因此,我的代码现在读取$photo_object=new photo();然后我调用这个方法,说$photos=$photo_object->find_all();然后我执行相同的foreach循环,但我回显$photo_object->variable bambol.jpg这是一些竹子的照片445 KB image/jpeg,然后我得到上面返回的10次。每个循环中给出的数据相同。函数“find_all”是否驻留在Photoshot类中?当您想在像find_all()这样的对象中调用函数时,必须指定objectinstance:$photo_object->find_all();很抱歉是的,我的全部都找到了。确实住在摄影班里,我在我的帖子里犯了一个错误。我本来打算把$photos=$photo\u object->find\u all()放在上面,而不是=find\u all()。它仍然不起作用,我只是一遍又一遍地从数据库中得到相同的结果。这就好像类中的变量在循环发生时不发生变化。在我看来,这就像ActiveRecord。您没有使用这些属性,因为您正在实现和讨论静态的存储库方法。我猜在收到一个对象后,您可以修改它,然后保存它,然后执行相对SQL。这是一个ORM的原始实现。好的,很好!:)你能展示你得到的输出,并解释你想要的输出是什么,它们之间的区别是什么吗?对。我已将代码改回在photo类中使用标准的find_all()。因此,我的代码现在读取$photo_object=new photo();然后我调用这个方法,说$photos=$photo_object->find_all();然后我执行相同的foreach循环,但我回显$photo_object->variable bambol.jpg这是一些竹子的照片445 KB image/jpeg,然后我得到上面返回的10次。每个循环中给出的相同数据非常感谢您,回答得很好。我现在明白了我的错误,现在我明白了,这似乎是很明显的。当我在写了多年程序性的东西之后开始我的OO编程之旅时,它让我忙了好几个月!我很高兴我能
public function find_all_photos() {
global $database;
$query = "SELECT * FROM {$this->table_name}";
$result = $database->query($query);
return $result;
}
public function find_by_sql($sql="") {
global $database;
$result = $database->query($sql);
$object_array = $database->fetch_array($result);
// Examine $object_array:
print '<pre>';
var_dump($object_array);
print '</pre>';
$object = $this->instantiate($object_array);
return $object_array;
}
//while($row = $database->fetch_array($result)) {
//$object_array[] = $this->instantiate($row);
//}
while( $row = $database->fetch_array($result) ) {
// Examine $row:
print '<pre>';
print_r( $row );
print '</pre>';
//$object_array[] = $this->instantiate($row);
}
private function instantiate($record) {
//Could check if $record exists and is an array
//Simple long form approach
//$object = new self;
$this->id= $record['id'];
$this->filename = $record['filename'];
$this->type = $record['type'];
$this->size = $record['size'];
$this->caption = $record['caption'];
}
/**
* A new class 'Photographs' to 'manage' the collection of photographs:
**/
class Photographs {
protected static $table_name="photographs";
public $photographObjects = array();
function __construct() {
// The constructor runs on creation/instantiation of the 'Photographs' object
print 'Photographs object created...';
}
// Retrieves the data and instantiates Photograph objects:
public function get_photographs() {
global $database;
$sql = "SELECT * FROM ". $this->table_name;
$this->photographObjects = array(); // empty the array before filling it
$result = $database->query($sql);
while( $row = $database->fetch_array( $result ) ) {
$tmpPhotograph = new Photograph();
$tmpPhotograph->id = $row['id'];
$tmpPhotograph->filename = $row['filename'];
// etc etc (or make the 'instantiate' function of the 'Photograph' class public, so you can do:
// $tmpPhotograph->instantiate($row);
// Now add a created and initialized object to your array:
$this->photographObjects[] = $tmpPhotograph;
}
}
// render the photographs:
public function render_photographs() {
if ( count($this->photographObjects) > 0 ) {
// loop through the objects in the photograpsObjects array:
foreach ( $this->photographObjects as $tmpPhotograph ) {
// in this line you can see that public properties (filename), and functions (image_path()) are available:
print '<img src="../' . $tmpPhotograph->image_path() . $tmpPhotograph->filename . '" width="100" />';
}
} else {
// Nothing found, inform the user:
print 'No photographs in array';
}
}
}
$photographManager = new Photographs();
$photographManager->get_photographs(); // retrieve them
$photographManager->render_photographs(); // output them
<?php foreach($photos as $photo): ?>
<?php foreach( $photographManager->photographObjects as $photo ): ?>