这是我在Stack Overflow中的第一篇文章,如果我不遵守任何规则,请耐心等待。我已经在php中编写了一段时间的脚本,但从未真正使用过任何OOP方面。我一直在线上进行培训课程(不确定我是否大声说出哪一个因为版权?)
无论哪种方式,程序员在他的一个班级中制作了一些静态方法,我决定我不想让我的静态。这是他在下面写的代码。我只是对代码中的变量有不同的引用,例如$ this-> variable。
`<?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().
}
}
?>`
^^这是他完整的照片()课,下面是我的照片课
<?php
//This class will use the database so wil need the database class included
require_once(LIB_PATH.DS.'database.php');
class Photograph extends DatabaseObject
{
public $table_name = "photographs";
public $id;
public $filename;
public $type;
public $size;
public $caption;
public $all_photos = array();
private $temp_path;
protected $upload_dir = "images";
public $errors=array();
protected $upload_errors = array (
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 Temp Directory.",
UPLOAD_ERR_CANT_WRITE => "Cant write file to disk.",
UPLOAD_ERR_EXTENSION => "File uploaded stopped by extension."
);
//Pass in $_FILE['uploaded_file'] as an argument
public function attach_file($file) {
//Perform error checking on the form params
if(!$file || empty($file) || !is_array($file)) {
//error: nothing uploaded or wrong argument
$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 forms params
$this->temp_path = $file['tmp_name'];
$this->filename = basename($file['name']);
$this->type = $file['type'];
$this->size = $file['size'];
//Dont worry about saving anything to database yet
return true;
}
}
public function save() {
//A new record wont have an id yet
if(isset($this->id)) {
$this->update();
//Really just to update the caption
} else {
//Make sure there are no errors
//Cant save if there are pre existing errors
if(!empty($this->errors)) { return false;}
//Make suer the caption is not to long for the database
if(strlen($this->caption) >= 255) {
$this->errors[] = "The caption can only be 255 characters long.";
return false;
}
//Cant save without the 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 that the file doesn't already exist in that 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()) {
//Were done with the temp path variable, The file isn't there any more
unset($this->temp_path);
return true;
}
} else {
//Error File was not moved
$this->errors[] = "The file upload failed, Possibly due to an incorrect permissions on upload folder.";
return false;
}
}
}
public function destroy($id,$filename) {
//First remove the database entry
if($this->delete($id)) {
//Then remove the file
$target_path = SITE_ROOT.DS.'public'.DS.$this->upload_dir.DS.$filename;
return unlink($target_path) ? true:false;
} else {
//Database delete failed
return false;
}
}
public function image_path() {
return $this->upload_dir.DS;
}
public function size_as_text($file_size) {
if($file_size < 1024) {
return "{$file_size} bytes";
} elseif($file_size < 1048576) {
$size_kb = round($file_size/1024);
return "{$size_kb} KB";
} else {
$size_mb = round($file_size/1048576, 1);
return "{size_mb} MB";
}
}
public function find_all() {
global $database;
$result = $this->find_by_sql("SELECT * FROM ".$this->table_name);
return $result;
}
public function find_all_photos() {
global $database;
$query = "SELECT * FROM {$this->table_name}";
$result = $database->query($query);
return $result;
}
public function find_by_id($id=0) {
global $database;
$result_array = $this->find_by_sql("SELECT * FROM " . $this->table_name . " WHERE id={$database->escape_value($id)} LIMIT 1");
return !empty($result_array) ? $result_array : false;
}
public function find_by_sql($sql="") {
global $database;
$result = $database->query($sql);
$object_array = $database->fetch_array($result);
$object = $this->instantiate($object_array);
//while($row = $database->fetch_array($result)) {
//$object_array[] = $this->instantiate($row);
//}
return $object_array;
}
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'];
//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) {
//get_object_vars returns an assocative array with all attributes
//Incl. pribate ones as the keys and their current values as the value
$object_vars = get_object_vars($this);
//We dont care about the value, we just want to know if the key exists
//Will return true or false
return array_key_exists($attribute,$object_vars);
}
public function create() {
//This is the create method
global $database;
//DOnt 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
$query = "INSERT INTO {$this->table_name} (";
$query .= "filename, type, size, caption";
$query .= ") VALUES ('";
$query .= $database->escape_value($this->filename) . "', '";
$query .= $database->escape_value($this->type) . "', '";
$query .= $database->escape_value($this->size) . "', '";
$query .= $database->escape_value($this->caption) . "')";
if($database->query($query)) {
$this->id = $database->insert_id();
return true;
} else {
return false;
}
}
public function update() {
global $database;
//Dont forget your sql good habits
//UPDATE table SET key='value', key='value' WHERE condition
//single quotes around all values
//Escape all values to prevent sql injection
$query = "UPDATE {$this->table_name} SET ";
$query .= "filename='" . $database->escape_value($this->filename) . "', ";
$query .= "type='" . $database->escape_value($this->type) . "', ";
$query .= "size='" . $database->escape_value($this->size) . "', ";
$query .= "caption='" . $database->escape_value($this->caption) . "'";
$query .= " WHERE id=" . $database->escape_value($this->id);
$database->query($query);
return ($database->affected_rows() ==1) ? true : false;
}
public function delete($id=0) {
global $database;
//Dont forget good sql habits
//DELETE FROM table WHERE condition LIMIT 1
//Escape all values to prevent sql injection
//Use limit 1
$query = "DELETE FROM {$this->table_name} ";
$query .="WHERE id=" . $database->escape_value($id);
$query .= " LIMIT 1";
$database ->query($query);
return ($database->affected_rows() ==1) ? true:false;
}
}
?>
然后他继续使用find_all()来获取view_photos.php页面上的照片表中的所有内容
$photos = Photograph::find_all();
?>
<?php include_layout_template('admin_header.php'); ?>
<h2>Photographs</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->image_path(); ?>" width="100" /> </td>
<td><?php echo $photo->filename; ?></td>
<td><?php echo $photo->caption; ?></td>
<td><?php echo $photo->size_as_text(); ?></td>
<td><?php echo $photo->type; ?></td>
<td><a href="delete_photo.php?id=<?php echo $photo->id; ? >">Delete</a></td>
</tr>
<?php endforeach; ?>
正如你所看到的,他对find_all()方法进行静态调用,然后循环遍历数组,使用存储在photos变量中的捕获数据列出数据库中的所有照片,使用其中的所有变量班级。下面是我的find_all()方法。
public function find_all() {
global $database;
$result = $this->find_by_sql("SELECT * FROM ".$this->table_name);
return $result;
}
当我做同样的事情,但有一个对象的实例照片
$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'); ?>
上面的代码输出
` 照片集:管理员
<tr>
<th>Image</th>
<th>Filename</th>
<th>Caption</th>
<th>Size</th>
<th>Type</th>
<th> </th>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
<tr>
<td><img src="../images\bamboo.jpg" width="100" /></td>
<td>bamboo.jpg</td>
<td>This is a photo of some bamboo</td>
<td>445 KB</td>
<td>image/jpeg</td>
<td><a href="delete_photo.php?id=1">Delete</a></td>
</tr>
</table>
<br />
<a href="photo_upload.php">Upload a new photograph</a>
</div>
<div id="footer">Copyright 2015, Ryan Hadley</div>
</body>
</html>
`
这种方法必须是静态的吗?或者我只是没有看到什么,我通过编写新方法来解决它
public function find_all_photos() {
global $database;
$query = "SELECT * FROM {$this->table_name}";
$result = $database->query($query);
return $result;
}
这可行,但我不使用类内的任何变量,而是调用我在foreach循环中创建的照片数组(foreach($ photos as $ photo))。这使得类中的属性看起来毫无意义。我这样做了吗?或者有什么东西我只是不了解对象?
谢谢你提前获得任何帮助
快乐编码
答案 0 :(得分:0)
现在的代码,将$object_array
传递给instantiate
。
但instantiate
构建为只接受从结果集中检索的一个row
。
如果您在传递之前检查$object_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;
}
关于以下注释行:
//while($row = $database->fetch_array($result)) {
//$object_array[] = $this->instantiate($row);
//}
我建议取消注释并检查$row
:
while( $row = $database->fetch_array($result) ) {
// Examine $row:
print '<pre>';
print_r( $row );
print '</pre>';
//$object_array[] = $this->instantiate($row);
}
关于函数instantiate
- 现在使用它的方式,每次调用它时,它都会设置自身的属性(id,filename ... etc)。
因此,最后一次调用此函数时,Photograph实例的属性值与传递给它的最后一个$record
的值相同。
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倍。
我写了一个例子来说明你如何去做你想要的事情(根据你的意见确定):
/**
* 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 ): ?>
我希望这能为你解决一些问题。