iT邦幫忙

DAY 23
10

逐步提昇PHP技術能力系列 第 23

逐步提昇PHP技術能力 - 逐步改善軟體架構 - 分離出頁面的邏輯

稍微調整了一下程式,讓功能完整一點,然後再來調整。

既然最常更動的往往是頁面,那讓頁面的邏輯跟其他部分混在一起,就很容易互相影響而不好修改。所以通常在改善架構的第一小步,就是先把頁面的邏輯拆出來。
拆開的步驟很簡單,就是把「非」頁面邏輯的PHP程式碼,一步一步依照順序搬到程式開始的地方。

比較複雜的部份,是查詢的迴圈跟網頁的邏輯混在一起的地方。這些地方,需要把迴圈改成兩個,查詢的迴圈中,把資料放進陣列變數。然後在頁面呈現的迴圈中,每次處理陣列中的一列資料,這樣就可以拆開了。

除了拆出頁面的邏輯,這個時候也可以順便處理頁面重複的地方。例如頁首跟頁尾是共用的,所以可以拆到獨立的檔案中,然後再include進來。

原本的程式:(index.php)

<?php
session_start();
if(isset($_SESSION['user']['account'])) {
	$member = true;
	$name = $_SESSION['user']['name'];
} else $member = false;
$conn = mysql_connect('localhost', 'root', '');
if(!$conn)
	die('mysql connection error.');

mysql_select_db('myforum');
if(isset($_SESSION['msg'])) {
	$message = mysql_real_escape_string($_SESSION['msg']);
	unset($_SESSION['msg']);
}
?>


	<table width="800" border="1" cellpadding="0" cellspacing="0" align="center">
		<!-- header start -->
		<tr>
			<th align="left">我的論壇</th>
		</tr>
		<tr>
			<td style="text-align:right" bgcolor="#336699">
				<table align="right">
					<tr>
<?php
if($member) {
?>
						<td>Welcome [<?php echo $name;?>] <button onclick='document.location.href="logout.php"'>登出</button></td>
<?php
} else {
?>
						<form method="post" action="login.php">
							<td>登入後可留言  </td>
							<td>帳號</td>
							<td><input type="text" name="account"></td>
							<td>密碼</td><td><input type="password" name="password"></td>
							<td><input type="submit" value="登入"></td>
						</form>
<?php
}
?>
					</tr>
				</table>
			</td>  
		</tr>
		<!-- header end -->
		<!-- content start-->
		<tr height="600">
			<td valign="top">
				<table width="100%" border="1" cellspacing="0" cellpadding="5">
					<tr bgcolor="#DDEEFF">
						<th>論壇名稱</th>
						<th>文章數</th>
						<th>最新文章</th>
						<th>操作</th>
					</tr>
<?php
	$sql = "SELECT f.*,count(a.forums_id) AS count  FROM forums f LEFT JOIN articles a ON a.forums_id = f.id GROUP BY a.forums_id ORDER BY f.id";
	$result = mysql_query($sql, $conn);
	$count = 0;
	while($row = mysql_fetch_array($result)) {
		if($count%2==0) {
			$style = 'bgcolor="#EEFFEE"';
		} else {
			$style = 'bgcolor="#FFFFFF"';
		}
		$sql = "SELECT * FROM articles WHERE forums_id=".$row['id']." ORDER BY id DESC LIMIT 1";
		$result1 = mysql_query($sql, $conn);
		$row1 = mysql_fetch_array($result1);
?>
					<tr <?php echo $style;?>>
						<td><?php echo $row['name'];?></td>
						<td><?php echo $row['count'];?></td>
						<td><?php echo $row1['title'];?></td>
						<td>
							<button onclick="document.location.href='forum.php?id=<?php echo $row['id'];?>'">進入</button>
						</td>
					</tr>
<?php
		$count++;
	}
?>
				</table>
			</td>
		</tr>
		<!-- content end -->
		<!-- footer start -->
		<tr bgcolor="#336699">
			<td align="center">
				<font color="#EFEFEF">Copyright 1899  by Fillano</font>
			</td>
		</tr>
		<!-- footer end -->
	</table>
<script>
<?php
if(isset($message)) {
?>
	alert('<?php echo $message;?>');
<?php
}
?>
</script>

然後開始把邏輯拆開。這裡其實會動到的程式碼,主要在資料查詢這一塊:

<?php
	$sql = "SELECT f.*,count(a.forums_id) AS count  FROM forums f LEFT JOIN articles a ON a.forums_id = f.id GROUP BY a.forums_id ORDER BY f.id";
	$result = mysql_query($sql, $conn);
	$count = 0;
	while($row = mysql_fetch_array($result)) {
		if($count%2==0) {
			$style = 'bgcolor="#EEFFEE"';
		} else {
			$style = 'bgcolor="#FFFFFF"';
		}
		$sql = "SELECT * FROM articles WHERE forums_id=".$row['id']." ORDER BY id DESC LIMIT 1";
		$result1 = mysql_query($sql, $conn);
		$row1 = mysql_fetch_array($result1);
		
?>
					<tr <?php echo $style;?>>
						<td><?php echo $row['name'];?></td>
						<td><?php echo $row['count'];?></td>
						<td><?php echo $row1['title'];?></td>
						<td>
							<button onclick="document.location.href='forum.php?id=<?php echo $row['id'];?>'">進入</button>
						</td>
					</tr>
<?php
		$count++;
	}
?>

先把資料查詢的迴圈跟頁面拆開,把資料存入一個陣列變數$data:

<?php
	$sql = "SELECT f.*,count(a.forums_id) AS count  FROM forums f LEFT JOIN articles a ON a.forums_id = f.id GROUP BY a.forums_id ORDER BY f.id";
	$result = mysql_query($sql, $conn);
	$count = 0;
	$data = array();
	while($row = mysql_fetch_array($result)) {
		if($count%2==0) {
			$style = 'bgcolor="#EEFFEE"';
		} else {
			$style = 'bgcolor="#FFFFFF"';
		}
		$sql = "SELECT * FROM articles WHERE forums_id=".$row['id']." ORDER BY id DESC LIMIT 1";
		$result1 = mysql_query($sql, $conn);
		$row1 = mysql_fetch_array($result1);
		$data[] = array('id'=>$row['id'], 'name'=>$row['name'], 'count'=>$row['count'], 'title'=>$row1['title'], 'style'=>$style);
		$count++;
	}
?>
					<tr <?php echo $style;?>>
						<td><?php echo $row['name'];?></td>
						<td><?php echo $row['count'];?></td>
						<td><?php echo $row1['title'];?></td>
						<td>
							<button onclick="document.location.href='forum.php?id=<?php echo $row['id'];?>'">進入</button>
						</td>
					</tr>
<?php
?>

然後在頁面部分,改成對這個陣列變數用foreach來迭代:

<?php
	$sql = "SELECT f.*,count(a.forums_id) AS count  FROM forums f LEFT JOIN articles a ON a.forums_id = f.id GROUP BY a.forums_id ORDER BY f.id";
	$result = mysql_query($sql, $conn);
	$count = 0;
	$data = array();
	while($row = mysql_fetch_array($result)) {
		if($count%2==0) {
			$style = 'bgcolor="#EEFFEE"';
		} else {
			$style = 'bgcolor="#FFFFFF"';
		}
		$sql = "SELECT * FROM articles WHERE forums_id=".$row['id']." ORDER BY id DESC LIMIT 1";
		$result1 = mysql_query($sql, $conn);
		$row1 = mysql_fetch_array($result1);
		$data[] = array('id'=>$row['id'], 'name'=>$row['name'], 'count'=>$row['count'], 'title'=>$row1['title'], 'style'=>$style);
		$count++;
	}
	foreach($data as $row) {
?>
					<tr <?php echo $row['style'];?>>
						<td><?php echo $row['name'];?></td>
						<td><?php echo $row['count'];?></td>
						<td><?php echo $row['title'];?></td>
						<td>
							<button onclick="document.location.href='forum.php?id=<?php echo $row['id'];?>'">進入</button>
						</td>
					</tr>
<?php
	}
?>

拆開以後,資料查詢的部份跟頁面已經沒有關係了,所以可以把它往前移,接近完工的程式就變成這樣:

<?php
session_start();
if(isset($_SESSION['user']['account'])) {
	$member = true;
	$name = $_SESSION['user']['name'];
} else $member = false;
$conn = mysql_connect('localhost', 'root', '');
if(!$conn)
	die('mysql connection error.');

mysql_select_db('myforum');
if(isset($_SESSION['msg'])) {
	$message = mysql_real_escape_string($_SESSION['msg']);
	unset($_SESSION['msg']);
}
$sql = "SELECT f.*,count(a.forums_id) AS count  FROM forums f LEFT JOIN articles a ON a.forums_id = f.id GROUP BY a.forums_id ORDER BY f.id";
$result = mysql_query($sql, $conn);
$count = 0;
$data = array();
while($row = mysql_fetch_array($result)) {
	if($count%2==0) {
		$style = 'bgcolor="#EEFFEE"';
	} else {
		$style = 'bgcolor="#FFFFFF"';
	}
	$sql = "SELECT * FROM articles WHERE forums_id=".$row['id']." ORDER BY id DESC LIMIT 1";
	$result1 = mysql_query($sql, $conn);
	$row1 = mysql_fetch_array($result1);
	$data[] = array('id'=>$row['id'], 'name'=>$row['name'], 'count'=>$row['count'], 'title'=>$row1['title'], 'style'=>$style);
	$count++;
}
?>


	<table width="800" border="1" cellpadding="0" cellspacing="0" align="center">
		<!-- header start -->
		<tr>
			<th align="left">我的論壇</th>
		</tr>
		<tr>
			<td style="text-align:right" bgcolor="#336699">
				<table align="right">
					<tr>
<?php
if($member) {
?>
						<td>Welcome [<?php echo $name;?>] <button onclick='document.location.href="logout.php"'>登出</button></td>
<?php
} else {
?>
						<form method="post" action="login.php">
							<td>登入後可留言  </td>
							<td>帳號</td>
							<td><input type="text" name="account"></td>
							<td>密碼</td><td><input type="password" name="password"></td>
							<td><input type="submit" value="登入"></td>
						</form>
<?php
}
?>
					</tr>
				</table>
			</td>  
		</tr>
		<!-- header end -->
		<!-- content start-->
		<tr height="600">
			<td valign="top">
				<table width="100%" border="1" cellspacing="0" cellpadding="5">
					<tr bgcolor="#DDEEFF">
						<th>論壇名稱</th>
						<th>文章數</th>
						<th>最新文章</th>
						<th>操作</th>
					</tr>
<?php
	foreach($data as $row) {
?>
					<tr <?php echo $row['style'];?>>
						<td><?php echo $row['name'];?></td>
						<td><?php echo $row['count'];?></td>
						<td><?php echo $row['title'];?></td>
						<td>
							<button onclick="document.location.href='forum.php?id=<?php echo $row['id'];?>'">進入</button>
						</td>
					</tr>
<?php
	}
?>
				</table>
			</td>
		</tr>
		<!-- content end -->
		<!-- footer start -->
		<tr bgcolor="#336699">
			<td align="center">
				<font color="#EFEFEF">Copyright 1899  by Fillano</font>
			</td>
		</tr>
		<!-- footer end -->
	</table>
<script>
<?php
if(isset($message)) {
?>
	alert('<?php echo $message;?>');
<?php
}
?>
</script>

可以看出,除了開頭這一段php之外,html中的php程式碼,都是在處理頁面的邏輯,資料都是倚賴php程式中產生的變數。試跑一下,程式沒有錯誤,然後就可以把php程式與html的部份進一步拆開成兩個檔案。為了管理方便,html部分就把它放到views目錄,然後再透過include引入。

完工的index.php:

<?php
session_start();
if(isset($_SESSION['user']['account'])) {
	$member = true;
	$name = $_SESSION['user']['name'];
} else $member = false;
$conn = mysql_connect('localhost', 'root', '');
if(!$conn)
	die('mysql connection error.');

mysql_select_db('myforum');
if(isset($_SESSION['msg'])) {
	$message = mysql_real_escape_string($_SESSION['msg']);
	unset($_SESSION['msg']);
}
$sql = "SELECT f.*,count(a.forums_id) AS count  FROM forums f LEFT JOIN articles a ON a.forums_id = f.id GROUP BY a.forums_id ORDER BY f.id";
$result = mysql_query($sql, $conn);
$count = 0;
$data = array();
while($row = mysql_fetch_array($result)) {
	if($count%2==0) {
		$style = 'bgcolor="#EEFFEE"';
	} else {
		$style = 'bgcolor="#FFFFFF"';
	}
	$sql = "SELECT * FROM articles WHERE forums_id=".$row['id']." ORDER BY id DESC LIMIT 1";
	$result1 = mysql_query($sql, $conn);
	$row1 = mysql_fetch_array($result1);
	$data[] = array('id'=>$row['id'], 'name'=>$row['name'], 'count'=>$row['count'], 'title'=>$row1['title'], 'style'=>$style);
	$count++;
}
include 'views/index.php';
?>

完工後的views/index.php:

	<table width="800" border="1" cellpadding="0" cellspacing="0" align="center">
		<!-- header start -->
		<tr>
			<th align="left">我的論壇</th>
		</tr>
		<tr>
			<td style="text-align:right" bgcolor="#336699">
				<table align="right">
					<tr>
<?php
if($member) {
?>
						<td>Welcome [<?php echo $name;?>] <button onclick='document.location.href="logout.php"'>登出</button></td>
<?php
} else {
?>
						<form method="post" action="login.php">
							<td>登入後可留言  </td>
							<td>帳號</td>
							<td><input type="text" name="account"></td>
							<td>密碼</td><td><input type="password" name="password"></td>
							<td><input type="submit" value="登入"></td>
						</form>
<?php
}
?>
					</tr>
				</table>
			</td>  
		</tr>
		<!-- header end -->
		<!-- content start-->
		<tr height="600">
			<td valign="top">
				<table width="100%" border="1" cellspacing="0" cellpadding="5">
					<tr bgcolor="#DDEEFF">
						<th>論壇名稱</th>
						<th>文章數</th>
						<th>最新文章</th>
						<th>操作</th>
					</tr>
<?php
	foreach($data as $row) {
?>
					<tr <?php echo $row['style'];?>>
						<td><?php echo $row['name'];?></td>
						<td><?php echo $row['count'];?></td>
						<td><?php echo $row['title'];?></td>
						<td>
							<button onclick="document.location.href='forum.php?id=<?php echo $row['id'];?>'">進入</button>
						</td>
					</tr>
<?php
	}
?>
				</table>
			</td>
		</tr>
		<!-- content end -->
		<!-- footer start -->
		<tr bgcolor="#336699">
			<td align="center">
				<font color="#EFEFEF">Copyright 1899  by Fillano</font>
			</td>
		</tr>
		<!-- footer end -->
	</table>
<script>
<?php
if(isset($message)) {
?>
	alert('<?php echo $message;?>');
<?php
}
?>
</script>

這樣要修改頁面時,只需要去改views/index.php,不用去改index.php了。另外,在修改views/index.php時,需要注意的就是使用的變數與邏輯是否跟之前一致,應該就可以正確執行。

======

在頁面更複雜以後,像這樣簡單的切割可能還不夠。早期最好的方案是使用smarty這個template engine,不過目前有更多好選擇,例如twig。明天就開始嘗試套用twig,並且把一些屬於頁面layout的部份與頁面內容的部份進一步拆開。


上一篇
逐步提昇PHP技術能力 - 逐步改善軟體架構 - 一個「古典」php論壇
下一篇
逐步提昇PHP技術能力 - 逐步改善軟體架構 - 使用樣板引擎
系列文
逐步提昇PHP技術能力30

2 則留言

0
badbayz
iT邦新手 4 級 ‧ 2016-06-20 16:16:49

學習中

我要留言

立即登入留言