我使用 array_reverse 将新创建的待办事项添加到列表顶部。但现在我无法删除它们。当我单击复选框删除项目时,它将删除列表另一端的项目。谁能告诉我扭转订单并让它们正确删除的最佳方法? array_reverse是实现这一目标的最佳方式,还是有更好的选择。我的两个文件在下面。
的index.php
fetch()
TaskList.php
<?php
// cookies
ini_set('session.gc_maxlifetime', 172800);
session_set_cookie_params(172800);
// array('get milk', 'feed dog');
include 'TaskList.php';
$list = new TaskList('tasks');
if(isset($_POST['task'])) {
// if post task is set the user submitted a task
$list->addItem($_POST['task']);
$list->save();
}
if(isset($_POST['delete'])) {
// delete this item from the array
$keys = $_POST['delete'];
foreach($keys as $key) {
array_reverse($list->deleteItem($key));
}
$list->save();
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>To Do List</title>
</head>
<body>
<h1>To Do List</h1>
<!-- Insert Items -->
<form action="index.php" method="post">
<label for="task">
Enter task: <input type="text" name="task" id="task" value="" placeholder="Enter Task Here">
</label>
<input type="submit" name="" value="Add">
</form>
<form class="" action="index.php" method="post">
<ul>
<?php foreach(array_reverse($list->items) as $key => $task): ?>
<!-- [] tell browser that it's an array and to delete more than one item at a time -->
<li><input type="checkbox" name="delete[]" value="<?php echo $key ?>"><?php echo $task; ?></li>
<?php endforeach; ?>
</ul>
<input type="submit" name="" value="Delete">
</form>
<hr>
<?php var_dump(array_reverse($list->items)) ?>
</body>
</html>
答案 0 :(得分:0)
这里可以使用 for 循环来通过向后循环来保持任务列表中项目的顺序。
我在TaskList类中添加了一个方便的方法来轻松访问键
function getKey($key) {
return $this->items[$key];
}
修改PHP模板以使用 for 循环:
<form class="" action="index.php" method="post">
<ul>
<?php
$count = count($taskList->items) - 1;
for($key=$count; $key >= 0; $key--) {
$task = $taskList->getKey($key);
?>
<li><input type="checkbox" name="delete[]" value="<?php echo $key ?>">
<?php echo $task; ?></li>
<?php } ?>
</ul>
<input type="submit" name="" value="Delete">
</form>
答案 1 :(得分:0)
这里的目标是删除数组中相反的元素。一种方法是使用array_keys
获取数组的键,然后在结果上使用array_reverse
为我们提供相反键的映射。
$reverseKeys = array_reverse(array_keys($arr));
// output of print_r($reverseKeys) for an array indexed from 0 to 4
Array
(
[0] => 4
[1] => 3
[2] => 2
[3] => 1
[4] => 0
)
然后我们可以使用此地图删除相应的元素。
if(isset($_POST['delete'])) {
// delete this item from the array
$keys = $_POST['delete'];
$reverseKeys = array_reverse(array_keys($arr));
foreach($keys as $key) {
$list->deleteItem($reverseKeys[$key]);
}
$list->save();
}
由于此问题具有oop
标记,我将尝试着重于提供更加面向对象的方法以及如何改进当前的设计。
TaskList
对象首先,让我们看看TaskList
对象的设计,看看我们可以改进哪些内容。
面向对象编程的关键概念之一( 对某些人来说最重要)是encapsulation的概念。简而言之,封装意味着对象的内部工作和属性对于使用该对象的代码是隐藏的。这在实践中意味着一个对象应该具有private
属性,并且只通过公共访问器公开它们(部分或全部)。
访问者可以返回没有修改的值
public function getDateOfBirth() {
return $this->dateOfBirth;
}
或执行一些修改以赋予数据更多意义
public function getAge() {
// assuming $dateOfBirth is an instance of DateTime
$diff = $dateOfBirth->diff(new DateTime());
return $diff->format('%y');
}
查看TaskList
类,我们可以将属性$items
和$listName
转换为私有成员,并为其创建访问者。
class TaskList {
private $items = [];
private $listname = '';
public function __construct($listname){
/* ... */
}
public function getListName() {
return $this->listName;
}
public function getItems() {
return $this->items;
}
}
班上其他人对我好看; addItem()
,deleteItem()
和save()
都非常不言自明,而且包含得很好。但其余的代码怎么样?查看index.php
文件,我们可以将其重构为TaskList
。最大的一个是执行批量删除的foreach
循环。 TaskList
类应该能够自己执行此操作,而不会将其内部结构暴露给其余代码。
// rename delete to deleteOne
public function deleteOne($key) {
unset $this->items[$key];
}
public function deleteItems($keys) {
foreach($keys as $key) {
$this->deleteOne($key);
}
}
// reverse delete from earlier
public function reverseDeleteItems($keys) {
$reverseKeys = array_reverse(array_keys($arr));
foreach($keys as $key) {
$this->deleteOne($reverseKeys[$key]);
}
}
在面向对象编程中经常应用的Antoher重要原则是Single Responsability。单一责任原则(SRP)没有详细说明,一个对象应该只处理自己的数据/进程,而不是在该范围之外。在这里,TaskList
的职责是维护任务列表。然而,它也在它的构造函数中处理php会话,这不属于它的责任。
的index.php:
<?php
session_start()
/* ... */
TaskList.php:
class TaskList {
/* ... */
public function __construct($name) {
$this->listname = $name;
if(isset($_SESSION[$this->listname])) {
$this->items = $_SESSION[$this->listname];
}
else {
$this->items = array();
}
}
上面应该有足够的信息来帮助您解决问题,但我想借此机会提供一些建议。
首先,$items
是一个简单的数组,现在效果很好,但将来可能会出现问题。数组可以包含任何内容,它可能不是正确的格式。你可以做的是创建一个Task
类,让Item
的每个元素实例化它。通过这种方式验证每个任务是否具有适当的元素变得非常容易,并且它也可以更好地扩展。
class Task {
private $name;
private $value;
private $priority; // value from 0 to 9
private $createdAt;
private $updatedAt;
public function __construct($name, $value, $priority = 5) {
$this->name = $name;
$this->value = $value;
$this->priority = $priority;
$now = new DateTime();
$this->createdAt = $now;
$this->updatedAt = $now;
}
public function getName() {
return $this->name;
}
public function getValue() {
return $this->value;
}
public function setValue($value) {
$this->value = $value;
$this->updatedAt = new DateTime();
}
public function getPriority() {
return $this->priority;
}
public function toArray() {
return [
'name' => $this->name,
'value' => $this->value,
'priority' => $this->priority,
'createdAt' => $this->createdAt->format('Y-m-d H:i:s'),
'updatedAt' => $this->updatedAt->format('Y-m-d H:i:s'),
];
}
}
这使您可以像这样修改add
函数
public function addItem($name, $value, $priority = null) {
// if items must be unique
if(array_key_exists($name, $this->items)) {
throw new Exception('An item with the same name already exists');
}
$this->items[$name] = new Task($name, $value, $priority);
}
正如您所看到的,我现在可以获得有关每个Task
的更多信息,只需对TaskList
类进行少量修改。
此外,您可以通过重构TaskList
中的保存机制来进一步提高TaskListRepository
,该机制将负责获取TaskList
的实例并将它们保存到您喜欢的任何系统(MySQL) ,SQLite,MongoDB,.txt文件,会话变量)。
class TaskListRepository {
public function save($list) {
/* store list */
}
public function getOne($name) {
/* fetch instance of a TaskList */
return $taskList;
}
}
您现在可以像这样修改index.php
<?php
session_start();
$taskListRepo = new TaskListRepository();
$taskList = $taskListRepo->getOne('myList');
$taskList->addOne('groceries', 'I need to pick up the groceries');
$taskListRepo->save($taskList);