<学習する内容>
独自の関数の作成する方法を学びます
なぜ関数を独自に作るかというと、同じ処理は必要な場合すべてのプログラムでその処理の記述となります。関数用ようファイルを作りそこに関数を記述して
各ページにはinclude()関数でこのファイルを読み込むだけであとは、設定した関数の記述だけでプログラムを書けためです。下記で解説し実際に5.2章に記述しているプログラム(saleslist_52.php)に適用させ体感しましょう。
1ー1)DBへの接続用関数
データベースの接続を関数化します。
関数を作成する前に2.10で作成したconn.phpようにDB」接続情報のみのファイルdb_info.phpを作成し
c:\xampp\data\へ配置します。
conn.phpとの違いは、mysqli_connect()の記述がありません。関数の中の変数を直接記述でも動きますが、ドキュメントルート内にIDやパスワードが
記載されたファイルを配置するのはセキュリティ的に不安があるためです。
<?php
//DB接続情報
$host = 'localhost'; //サーバ名
$user = 'root'; //ユーザ名
$pass = '********'; //DBのパスワード(自環境のパスワードに書き換えのこと)
$dbnm = 'sales'; //データベース名
?>
関数を関数用のファイル(function.php)を作成し記述します。
<記述方法>
<?php
//DB接情報読込
require_once("/xampp/data/db_info.php");
function connectDB() {
//グローバル変数(DB接続用)
global $conn; //DB接続 関数外での利用
global $host; //ホスト名 関数外の変数
global $user; //ユーザ名 関数外の変数
global $pass; //パスワード 関数外の変数
global $dbnm; //データベース名 関数外の変数
$conn = mysqli_connect($host,$user,$pass,$dbnm) or die("失敗です");
if (!$conn) {
echo "ErrNo[".mysqli_connect_errno()."]".mysqli_connect_error()."
";
exit;
}
}
?>
<解説>
関数を設定する際は必ずfunction と記述しその後に関数名(任意で上記の場合はconnectDB())を記述します。
その後{ }内に処理内容を書いていきます。
いきなりglobal という単語が出てきました。関数内で設定された変数は関数内でしか使えません。その逆で関数外で設定された変数も同様です。
変数の前にglobalと記述があると、この変数は関数の内外で利用できる変数となります。このように定義された変数をグローバル変数といいます。
SQLを動かす関数に、mysqli_query($sql,$conn) or die("error $sql");がありますが、ここで
$conn使われてます。
グローバル変数に定義されていないとエラーになってしまいます。また$hostもinclude('/xampp/data/conn.php');内で定義された変数です。
これは関数外なので関数内では使えません。よって関数内でグローバル変数に定義し利用できようにしてます。
その後処理は、$conn = mysqli_connect($SERV,$USER,$PASS,$dbnm) or die("失敗です"); を定義し失敗時はエラーコードとエラー内容を画面に表示させるようにしてます。
mysqli_connect_errno() エラーコード
mysqli_connect_error() エラー内容
関数の利用
php文にconnectDB();記述だけで利用できます。
・・・・・・・
//DBへの接続
//include('/xampp/data/conn.php'); この記述は削除します。
//関数ファイル読込
include_once('/xampp/htdocs/function.php');
//DB接続
connectDB();
・・・・・・・
<解説>
4行目にincludeは削除します。
7行目に関数ファイルを読み込みます。このincludeには_onceが付加されてます。これは一度読み込んだファイルがあれば
重複して読み込まないようにします。
10行目にconnectDB();のDB接続関数を呼出しプログラムに反映させます。
この場合、5.2章のプログラムより2行も追記になって意味が無いように思われますが、プログラムのやる内容が増えると関数も増えます。
増えた関数は、関数用のファイルに記述することにより関数を一元管理できることと、このファイルを読み込ませておけば独自関数がそのまま使えるメリットがあります。
<留意点、注意点>
・関数は利用するプログラムにも記述できます。また、プログラムのどの順番(前半でも後半でも)に記述しても利用できます。
・同じ関数が複数記述(呼出し)の場合エラーでプログラムが動きません。
2-1)部課検索のoption表示
部課検索用のプルダウン表示を関数化します。
<記述方法>
・・・・・・・
function sectionOPTION() {
global $conn;
$sql = "SELECT sectionName
,sectionCode
FROM Msection
;";
$res = mysqli_query($conn, $sql);
while ($row = mysqli_fetch_array($res)) {
$option .= "¥n".'<option value="'.$row["sectionCode"].'">'.$row["sectionName"];
}
return $option;
}
・・・・・・・
<解説>
関数名をsectionOPTION() として{ } 内処理を記述しております。
中にMsection(部課テーブル)よりsectionCodeとsectionNameを抽出するSQL文があります。
この抽出したデータを元に、HTMLのoption文を$potion(命名は任意)という変数に代入してます。
最後にreturn ;にて結果を戻しています。※¥nとは改行キーを文字にしたものです。なくても関数として動きますが、
ブラウザでソース見た時<option文が改行されずに横に表示されます。
<関数の利用>
<?php
//関数ファイル読込
include_once($_SERVER['DOCUMENT_ROOT'].'/function.php');
//部課検索OPTION取出し
$OPTION_SECTION = sectionOPTION();
・・・・・・・
<解説>
この戻された(戻り値)$optionを = sectionOPTION();として
取出し利用します。
include文を少し変えてます。
$_SERVER['DOCUMENT_ROOT'] はサーバ変数といい、設定されたWebサーバのドキュメントルートの情報が入ってます。
みなさんが第1章で設定されたWebの情報は/xampp/htdocsになります。echo文で echo $_SERVER['DOCUMENT_ROOT'];で
中身を確認してください。
2-2)選択部課の部署名の抽出
選択された部課の部署名の抽出を関数化します。
<記述方法>
・・・・・・・
function getSection() {
global $conn;
//戻り値の初期値設定
$sectionCode = null; //部署コード
$sectionName = null; //部署名
//POSTデータ取得し、データが取得できなかった場合デフォルト値を設定
if (isset($_POST["select_sectionCode"])) {
$sectionCode = $_POST["select_sectionCode"];
}
$sql = "SELECT sectionName
FROM Msection
WHERE sectionCode = $sectionCode
;";
$res = mysqli_query($conn, $sql) or die("[Error(section)] $sql");;
$row = mysqli_fetch_array($res);
$sectionName = $row["sectionName"];
return array ($sectionCode, $sectionName);
}
・・・・・・・
<解説>
関数名をgetSection() として{ } 内処理を記述しております。。
POSTで送信されたデータを$setionCodeに代入し16行目のSQL文にて部署名を抽出し$sectionNameに代入します。
これらのデータをを配列 array ($sectionCode, $sectionName)としてreturnで戻します。
<関数の利用>
・・・・・・・
//関数ファイル読込
include_once($_SERVER['DOCUMENT_ROOT'].'/function.php');
//検索指定されたselect_sectionCodeからの部課名の取出し
list($select_sectionCode,$sectionName) = getSection();
・・・・・・・
<解説>
この戻された(戻り値)list($select_sectionCode,$sectionName) = getSelectSection();として
取出し利用します。list関数とは、配列で代入された(戻された)値を変数に格納してくます。
return array ($sectionCode, $sectionName); で配列のデータを戻します。
↓
list($select_sectionCode,$sectionName) = getSelectSection(); で取り出します。
2-3)選択部署のWHERE句の生成
選択された部課のWHERE句生成を関数化します。
<記述方法>
・・・・・・・
function whereSection($sectionCode) {
global $conn;
$where = "AND sectionCode =$sectionCode";
return $where;
}
・・・・・・・
<解説>
関数の()の中に変数があります。これは引数と呼ばれるもので関数に対する入力値となります。
関数定義での()内の変数名は任意に設定できます。下記のPGのwhereSection($select_sectionCode)では
POSTで送信しされた部署コード$select_sectionCodeを設定してます。そして関数内ではここに記載された値が変数として
$sectionCodeとして使える設定としてます。
ややこしいですがまとめると
関数設定のfunction whereSection($sectionCode) → の関数内で使える変数$sectionCode
PG内の関数呼び出しのwhereSection($select_sectionCode); → 入力値(このケースはPOST送信された部署コード)
となります。
引数として登録された変数をSQL文のWHERE句を生成しreturnでPGへ戻します。
<関数の利用>
・・・・・・・
$where_and_section = whereSection($select_sectionCode);
・・・・・・・
<解説>
検索設定された部課コードをwhereSection関数の($select_sectionCode)を関数でreturnで戻されたWHERE句$where_and_sectionが代入されます。
3-1)営業担当者の検索用関数を作成
部署と同様に営業担当者のOPTION文、担当者抽出、WHERE句生成を関数化します。
<記述方法>
・・・・・・・
//OPTOIN文生成関数
function staffOPTION($sectionCode) {
global $conn;
$sql = "SELECT lastName
,staffCode
FROM Mstaff
WHERE sectionCode = $sectionCode
;";
$res = mysqli_query($conn, $sql) or die("[Error] $sql");
while ($row = mysqli_fetch_array($res)) {
$option .= "¥n".'<option value="'.$row["staffCode"].'">'.$row["lastName"];
}
//課全体追加対応
$option .= "¥n".'<option class="clr2" value="">課全体';
}
return $option;
・・・・・・・
//選択担当者の担当者名の抽出
function getStaff() {
global $conn;
//戻り値の初期値設定
$staffCode = null; //担当者コード
$staffName = null; //担当名
if (isset($_POST["select_staffCode"])) {
$staffCode = $_POST["select_staffCode"];
}
$sql = "SELECT staffName
FROM Mstaff
WHERE staffCode = $staffCode;";
$res = mysqli_query($conn, $sql);
$row = mysqli_fetch_array($res);
$staffName = $row["staffName"];
return array ($staffCode, $staffName);
}
//選択担当者のWHERE句生成関数
function whereStaff($staffCode) {
global $conn;
$where = "AND staffCode =$staffCode";
return $where;
}
3-2)営業担当者の検索用関数をPGに反映
・・・・・・・
//OPTION文の生成
$OPTION_STAFF = staffOPTION($select_sectionCode);
//選択された営業担当者の抽出
list($select_staffCode, $selectStaffName) = getStaff($staffCode);
//営業担当者のWHERE句の生成
$where_and_staff = whereStaff($select_staffCode);
・・・・・・・
4-1)関数をまとめてfunction.phpに記述
下記のサンプルプログラムをコピーもしくはダウンロードし指定のフォルダーに配置してください。
ファイル名:function.php
配置先URL:
http://localhost/function.php
<?php
//DB接情報読込
require_once("/xampp/data/db_info.php");
//DB接続関数
function connectDB() {
//グローバル変数(DB接続用)
global $conn; //DB接続
global $host; //ホスト名
global $user; //ユーザ名
global $pass; //パスワード
global $dbnm; //データベース名
$conn = mysqli_connect($host,$user,$pass,$dbnm) or die("失敗です");
if (!$conn) {
echo "ErrNo[".mysqli_connect_errno()."]".mysqli_connect_error()."
";
exit;
}
}
//部課検索option文生成
function sectionOPTION() {
global $conn;
if (empty($sectionCode)) {
$sectionCode = null;
$sectionName = '部署検索';
} else {
$sql = "SELECT sectionName
FROM Msection
WHERE sectionCode = $sectionCode
;";
$res = mysqli_query($conn_demo, $sql) or die("[Error(section)] $sql");
$row = mysqli_fetch_array($res);
$sectionName = $row["sectionName"];
}
return $option;
}
//選択部署名抽出
function getSection() {
global $conn;
//戻り値の初期値設定
$sectionCode = null; //部署コード
$sectionName = null; //部署名
//POSTデータ取得し、データが取得できなかった場合デフォルト値を設定
if (isset($_POST["select_sectionCode"])) {
$sectionCode = $_POST["select_sectionCode"];
}
if (empty($sectionCode)) {
$option = null;
} else {
$sql = "SELECT lastName
,staffCode
FROM Mstaff
WHERE sectionCode = $sectionCode
;";
$res = mysqli_query($conn_demo,$sql) or die("[Error] $sql");
while ($row = mysqli_fetch_array($res)) {
$option .= "
".'<option value="'.$row["staffCode"].'">'.$row["lastName"];
}
//全部署選択
$option .= "
".'<option value="">全社';
}
return array ($sectionCode, $sectionName);
}
//選択部署WHERE句生成
function whereSection($sectionCode) {
if (empty($sectionCode)) {
$where = null;
}else {
$where = "AND a.sectionCode = $sectionCode";
}
return $where;
}
//OPTOIN文生成関数
function staffOPTION($sectionCode) {
global $conn;
$option = null;
if (estrlen($sectionCode))
$sql = "SELECT lastName
,staffCode
FROM Mstaff
WHERE sectionCode = $sectionCode
;";
$res = mysqli_query($conn,$sql) or die("[Error] $sql");
while ($row = mysqli_fetch_array($res)) {
$option .= "
".'<option value="'.$row["staffCode"].'">'.$row["lastName"];
}
//課全体追加対応
$option .= "
".'<option value="">課全体';
}
return $option;
}
//選択担当者の担当者名の抽出
function getStaff() {
global $conn;
//戻り値の初期値設定
$staffCode = null; //担当者コード
$staffName = null; //担当名
if (isset($_POST["select_staffCode"])) {
$staffCode = $_POST["select_staffCode"];
}
if (empty($staffCode)) {
$staffName = '担当検索';
} else {
$sql = "SELECT staffName
FROM Mstaff
WHERE staffCode = $staffCode;";
$res = mysqli_query($conn, $sql);
$row = mysqli_fetch_array($res);
$staffName = $row["staffName"];
}
return array ($staffCode, $staffName);
}
//選択担当者のWHERE句生成関数
function whereStaff($staffCode) {
if (empty($staffCode)) {
$where = null;
} else {
$where = "AND a.staffCode = $staffCode";
}
return $where;
}
?>
4-2)5.2の売上一覧に反映
下記のサンプルプログラムをコピーもしくはダウンロードし指定のフォルダーに配置してください。
ファイル名:function.php
配置先URL:
http://localhost/function.php
<?php
//関数ファイル読込
include_once('/xampp/htdocs/function.php');
//DB接続(関数)
connectDB();
//POSTの受信
$fnc = filter_input(INPUT_POST, 'fnc');
$select_id = filter_input(INPUT_POST, 'select_id');
$select_date = filter_input(INPUT_POST, 'select_date');
//年度option
$day = date("Y-m-01"); //当月1日
$day = '2024-04-01'; //デモ用のデータ(2024年度)を表示のため記述
$num = 10; //表示期数
for ($i = 0;$i <= $num;$i++) {
$s = $i * 6; //半期6か月毎
$FY = date("Y",strtotime("-$s month",strtotime($day)));
$month = date("n",strtotime("-$s month",strtotime($day)));
$date = date("Y-m-d",strtotime("-$s month",strtotime($day)));
$opt_date = null;
if ($month >= 4 and $month < 10){
$opt_date .= '<option value="'.$date.'" >'.$FY.'上期';
} else {
$opt_date .= '<option value="'.$date.'" >'.$FY.'下期';
}
}
//年度表示と検索用データ生成
if (empty($select_date)){
$select_date = $day;
}
$selectFY = date("Y",strtotime($select_date));
$n = date("n",strtotime($select_date)); //1桁月
if ($n >= 4 and $n < 10) {
$startDate = $selectFY.'-04-01';
$endDate = $selectFY.'-10-01';
$term = '上期';
$select_date_display = $selectFY.$term;
} else {
$selectFY1 = $selectFY + 1;
$startDate = $selectFY.'-10-01';
$endDate = $selectFY1.'-04-01';
$term = '下期';
$select_date_display = $selectFY.$term;
}
for ($i = 0;$i <= 6;$i++) {
$ARY_MONTH[$i] = date("Ym",strtotime("+$i month",strtotime($select_date)));
$ARY_MONTH_INDEX[$i] = date("Y年n月",strtotime("+$i month",strtotime($select_date)));
if ($i == 6) { //半期計値用
$ARY_MONTH[$i] = 'sum';
$ARY_MONTH_INDEX[$i] = $term.'計';
}
}
//部署option(関数)
$OPTION_SECTION = sectionOPTION();
//部署検索(関数)
list($select_sectionCode,$select_sectionName) = getSection();
//部署WHERE句(関数)
$where_and_section = whereSection($select_sectionCode);
//OPTION文の生成(関数)
$OPTION_STAFF = staffOPTION($select_sectionCode);
//選択された営業担当者の抽出(関数)
list($select_staffCode, $select_staffName) = getStaff();
//営業担当者のWHERE句の生成(関数)
$where_and_staff = whereStaff($select_staffCode);
//$_POSTデータの保持
$OPT_DATA = null;
$OPT_DATA .= '<input type="hidden" name="select_sectionCode" value="'.$select_sectionCode.'">';
$OPT_DATA .= '<input type="hidden" name="select_staffCode" value="'.$select_staffCode.'">';
$OPT_DATA .= '<input type="hidden" name="select_date" value="'.$select_date.'">';
//HTMLテーブル項目(年月)代入
$HTML = null;
$HTML .= '<tr bgcolor="#D3D3D3" style="height:24px;" align="center">';
$HTML .= ' <td width="100" rowspan="2">部署</td>';
$HTML .= ' <td width="90" rowspan="2">担当者</td>';
for ($i = 0;$i < count($ARY_MONTH); $i++) {
$HTML .= '<td width="160" colspan="2">'.$ARY_MONTH_INDEX[$i].'</td>';
}
$HTML .= '</tr>';
//HTMLテーブル項目(売上・利益)代入
$HTML .= '<tr bgcolor="#D3D3D3" style="height:24px;" align="center">';
for ($i = 0;$i < count($ARY_MONTH); $i++) {
$HTML .= '<td>売上</td>';
$HTML .= '<td>利益</td>';
}
$HTML .= '</tr>';
//データ抽出&HTML代入
$sql = "SELECT sum(sales) AS sales
,sum(profit) AS profit
,staffCode
,EXTRACT(YEAR_MONTH FROM salesDate) AS salesMonth
FROM saleslist
WHERE salesDate >= '$startDate'
AND salesDate < '$endDate'
GROUP BY staffCode,salesMonth
;";
$res = mysqli_query($conn,$sql) or die("er SELECT $sql");
while($row = mysqli_fetch_array($res)){
$staffCode = $row["staffCode"];
$month = $row["salesMonth"];
$sales[$staffCode][$month] = $row["sales"];
$profit[$staffCode][$month] = $row["profit"];
$DETAIL[$staffCode][$month] = "<a onclick=\"window.open('sales_detail.php?select_staffCode=".$staffCode."&select_salesMonth=".$month."', 'detail','width=800, height=300, menubar=no, toolbar=no, scrollbars=yes');\">";
//半期計集計
if (isset($sales[$staffCode]['sum'])) {
$sales[$staffCode]['sum'] += $row["sales"];
$profit[$staffCode]['sum'] += $row["profit"];
}
$sales[$staffCode]['sum'] = $row["sales"];
$profit[$staffCode]['sum'] = $row["profit"];
}
//担当データよりHTML文の生成
$sql = "SELECT a.staffCode,a.staffName,b.sectionName FROM Mstaff as a
LEFT JOIN Msection AS b ON a.sectionCode = b.sectionCode
WHERE a.staffCode > 0
$where_and_section
$where_and_staff
ORDER BY a.sectionCode,a.staffCode;";
$res_staff = mysqli_query($conn,$sql) or die("er SELECT $sql");
while($row_staff = mysqli_fetch_array($res_staff)){
$staffCode = $row_staff["staffCode"];
$staffName = $row_staff["staffName"];
$sectionName = $row_staff["sectionName"];
$HTML .= '<tr bgcolor="white" style="height:24px;" align="right">';
$HTML .= ' <td align="center">'.$sectionName.'</td>';
$HTML .= ' <td align="center">'.$staffName.'</td>';
for ($i = 0;$i < count($ARY_MONTH);$i++) {
if ($i == 6) {
$ARY_MONTH[$i] = 'sum';
}
//数値フォーマット
if (isset($sales[$staffCode][$ARY_MONTH[$i]])) {
$sales[$staffCode][$ARY_MONTH[$i]] = number_format($sales[$staffCode][$ARY_MONTH[$i]]/1000);
$detail = null;
if (isset($DETAIL[$staffCode][$ARY_MONTH[$i]])) {
$detail = $DETAIL[$staffCode][$ARY_MONTH[$i]];
}
$HTML .= ' <td>'.$detail.$sales[$staffCode][$ARY_MONTH[$i]].'</a></td>';
} else {
$HTML .= ' <td></td>';
}
if (isset($profit[$staffCode][$ARY_MONTH[$i]])) {
$profit[$staffCode][$ARY_MONTH[$i]] = number_format($profit[$staffCode][$ARY_MONTH[$i]]/1000);
$HTML .= ' <td>'.$profit[$staffCode][$ARY_MONTH[$i]].'</td>';
} else {
$HTML .= ' <td></td>';
}
}
$HTML .= '</tr>';
}
//HTML本文
echo <<<EOT
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="/style.css" type="text/css">
<style>
a:hover {
color: red;
font-weight:bold;
}
</style>
<title>売上一覧</title>
</head>
<body>
売上一覧
<table style="font-size:12px;">
<tr style="height:24px;" align="center">
<form method="POST" action="{$_SERVER['PHP_SELF']}">
{$OPT_DATA}
<td width="70">
<SELECT name="select_date" onchange="submit(this.form)" style="width:100px;height:26px;">
<option value="{$select_date}" selected>{$select_date_display}
{$opt_date}
</select>
</td>
</form>
<form method="POST" action="{$_SERVER['PHP_SELF']}">
{$OPT_DATA}
<input type="hidden" name="select_staffCode" value="">
<td width="70">
<SELECT name="select_sectionCode" onchange="submit(this.form)" style="width:100px;height:26px;">
<option value="{$select_sectionCode}" selected>{$select_sectionName}
{$OPTION_SECTION}
</select>
</td>
</form>
<form method="POST" action="{$_SERVER['PHP_SELF']}">
{$OPT_DATA}
<td width="70">
<SELECT name="select_staffCode" onchange="submit(this.form)" style="width:100px;height:26px;">
<option value="{$select_staffCode}" selected>{$select_staffName}
{$OPTION_STAFF}
</select>
</td>
</form>
<td width="800"></td>
<td>単位:千円</td>
</tr>
</table>
<table bgcolor="#a9a9a9" cellspacing="1px" style="font-size:12px;" >
{$HTML}
</table>
<br>
</body>
</html>
EOT;
?>
<解説>
関数の利点としてプログラムが簡素化されることと、他のページ含めてよく使うような機能は関数としてまとめると
プログラムの記述が楽(効率化)になります。
注意事項は、プログラムエラーになるケースとして、定義されていない関数を記述や同じ関数を定義の記述
include文で関数を読み込んでいるのにプログラムで再度記述)があります。