質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

3回答

1006閲覧

PHPでファイル操作処理を一般化する関数func_registを作成したい

d__..___

総合スコア18

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2020/05/19 05:20

編集2020/05/19 09:17

ファイル操作処理を一般化する関数func_registを作成したい

今回作成したのはlog.datに 名前、年齢、電話番号を<>で区切って登録するプログラムです。
すでに登録してある場合はエラーを出します。

この処理を一般化し、好きなファイル名、任意の配列、チェックするデータ、重複時のメッセージを関数として処理を作りたいです。
どのようにすればよいでしょうか?

今回一般化したい処理は$file , $insertの部分、重複チェックする変数,重複時メッセージ
の4つです。

まず、一般化する前の処理を記載します。

PHP

1$name = "田中太郎"; 2$age = "15"; 3$tel = "09012345678"; 4 5 6$file = "./log.dat"; 7$file_array = file($file); 8foreach($file_array as $value){ 9list($list_name,$list_age,$list_tel) = explode('<>', $value); 10if($name == $list_name){ 11$flag = 1; 12} 13} 14if($flag) exit("お客様のお名前は登録済みです。"); 15$fp = fopen($file ,"r+") or exit("log.datが開けません"); 16if($fp && flock($fp, LOCK_EX)){ 17$insert = implode('<>', array($name,$age,$tel,"\n")); 18array_unshift($file_array,$insert); 19rewind($fp); 20ftruncate($fp,0); 21for($i=0; $i<count($file_array); $i++) { 22fwrite($fp, $file_array[$i]); 23} 24fclose($fp); 25} 26echo "登録しました。";

一般化する前のこの処理を実行すれば新規登録の場合は「登録しました」と表示されます。
次に一般化する関数func_registを作成した際には
使うときには

PHP

1$name = "田中太郎"; 2$age = "15"; 3$tel = "09012345678"; 4$file = "./log.dat"; 5$list = array($name,$age,$tel); 6$errmsg = "お客様のお名前は登録済みです。"; 7func_regist($file,$list,$check,$errmsg);

一般化していると、これを次のように使えるようにしたいです。

生徒の名前<>学年<>テストの成績
をscore.datに保存する。新しく追加するときは  $student_name , $rank , $score として追加する
例として、山田太郎君、小学6年生、80点とします。

PHP

1$name = "山田次郎"; 2$rank = "6"; 3$score = "80"; 4$file = "./score.dat"; 5$data = list($name,$rank,$score); 6$check = $name; 7$errmsg = "その生徒の名前は登録済みです"; 8func_regist($file,$data,$check,$errmsg);

このfunc_regist関数にはどのように書けばよいか教えてください。

追記:自分で作ってみたコードです。

PHP

1list($list_name,$list_age,$list_tel) = explode('<>', $value);

と書いていたところを一般化するときは

PHP

1$list_name,$list_age,$list_tel

をデータとして渡す必要があります
それがわかりません。

また、これが渡せないと
重複のチェックであるこの部分がかけません。

PHP

1if($name == $list_name){ 2$flag = 1; 3}

PHP

1name = "田中太郎"; 2$age = "15"; 3$tel = "09012345678"; 4$insert = implode('<>', array($name,$age,$tel,"\n")); 5$data = array($name,$age,$tel); 6 7func_regist("./log.dat",$data,$name,$insert,"その生徒の名前は登録済み"); 8 9 10 11function func_regist($file , array $data , $check, $insert,$errmsg){ 12$file_array = file($file); 13foreach($file_array as $value){ 14//list($data) = explode('<>', $value); 15//この処理をどうすればよいか 16echo "list_name:".$list_name; 17if($name == $list_name){ 18$flag = 1; 19} 20} 21if($flag) exit($errmsg); 22$fp = fopen($file ,"r+") or exit("{$file}が開けません"); 23if($fp && flock($fp, LOCK_EX)){ 24array_unshift($file_array,$insert); 25rewind($fp); 26ftruncate($fp,0); 27for($i=0; $i<count($file_array); $i++) { 28fwrite($fp, $file_array[$i]); 29} 30fclose($fp); 31} 32echo "登録しました。"; 33 34 35 36} 37

ここの処理をどうかくか の部分を教えてください

list()の中身は変数として1つ1つしかいれられません。
list (array ($data)) = explode('<>', $value);
とできたら理想なのですが・・・

listで分割する変数を関数外から呼び出したいです。
ループの中で
echo "list_name:".$list_name;
と出力してもNULLになります。
2回目のアクセス時にはlist_nameにはすでに登録されている「田中太郎」と出力されたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tanat

2020/05/19 08:20

func_regist($file,$list,$check,$errmsg); まで仕様が決まっているのであれば、あんまり悩む要素は無い様に思いますが、不明な点はどういうところでしょうか?
d__..___

2020/05/19 08:21

list(変数1,変数2)... とあるのですが変数を渡せません・
tanat

2020/05/19 08:31 編集

元のコードの該当部分についての挙動は正確に把握されていますか? *質問は編集可能なので、以下について追記をお願いします。 1. func_registの中身を実際にどう書いてみたのか 2. どうやってデバッグして「list(変数1,変数2)...とあるのですが変数を渡せません・」という不明点に行き当たったのか。
d__..___

2020/05/19 08:58

中身を掲載しました。確認お願いします
退会済みユーザー

退会済みユーザー

2020/05/19 11:05 編集

目を離した隙にコードが変わってたか、おっとっと。
退会済みユーザー

退会済みユーザー

2020/05/19 12:19

動作確認を取ったコードを追記したあとで気づいたけど、 $insert ってなんだ?
d__..___

2020/05/19 12:20

insertは新しく追加するデータです。 名前、年齢、電話番号を<>で区切って登録します。 今回は山田太郎でしたけど、フォームから任意のユーザー情報を登録します
guest

回答3

0

php

1$name = "田中太郎"; 2$age = "15"; 3$tel = "09012345678"; 4$file = "./log.dat"; 5$list = array($name,$age,$tel); 6$errmsg = "お客様のお名前は登録済みです。"; 7func_regist($file,$list,$check,$errmsg);

このコードに$checkが出てこないの、なんでだろう?

php

1$name = "山田次郎"; 2$rank = "6"; 3$score = "80"; 4$file = "./score.dat"; 5$data = list($name,$rank,$score); 6$check = $name; 7$errmsg = "その生徒の名前は登録済みです"; 8func_regist($file,$data,$check,$errmsg);

どちらのコードにも共通して、
登録用関数を呼び出す前からなぜエラーメッセージを引き渡す必要があるのかもわからないですね。

引数の参照渡しの項を読んでもらいたいのですが、
通常なんの工夫もなく引数を関数に与えると「値渡し」となって、
関数内でいくら書き換えても揮発して呼び出し元には何も影響を与えないのですが、
「参照渡し」として関数内で書き換えれば呼び出し元に返すことができたりします。
だから、例えば$errmsgの初期値はカラ文字列にして、
エラー発生時にはエラーメッセージを関数内で詰めるというやり方もあるんじゃないかと。

あと、3番目の引数$checkって必要ですか?
$dataの中に$nameを持たせているのだから冗長です。

また、やたらexit();を使ってますが、
ユーザー定義関数内で似たようなことをするために、
例えば、
$errmsgにエラー内容を代入した後、
return false;などとすればいいんじゃないかと。

func_regist()が返す値がfalseのときは何らかのエラーが発生した、
trueなら成功した、などと判定すれば、
falseだからエラーメッセージを表示しようってなりますよね。
登録用関数func_regist()内で勝手にエラーメッセージを表示されても困るでしょうし。

提案ですが、
配列の構文の例にあるような、
key => value
的なデータのもたせ方の方が楽な気がします。

php

1$data = [ 2 'name' => "山田次郎", 3 'rank' => 6, 4 'score' => 80, 5]; 6echo $data['name']; // "山田次郎"

一応、改良したコードを手元で書いていますが、
もうちょっと寝かせておきます。


最小限(?)改変してます、動作確認取ったやーつー。

php

1<?php 2$name = "山田次郎"; 3$rank = "6"; 4$score = "80"; 5$file = "./262908_score.dat"; 6$data = [$name, $rank, $score]; 7$check = $name; 8$errmsg = ""; 9$result = func_regist($file, $data, $errmsg); 10echo $errmsg; 11 12function func_regist($file, $data, &$errmsg) { 13 $file_array = file($file); 14 $flag = 0; 15 foreach ($file_array as $value) { 16 list($list_name, $list_age, $list_tel) = explode('<>', rtrim($value)); // rtrim()で改行コード撲滅 17 if ($data[0] === $list_name) { 18 $flag = 1; 19 break; 20 } 21 } 22 if ($flag === 1) { 23 $errmsg = "名前は登録済みです。"; 24 return false; 25 } 26 $fp = fopen($file ,"r+"); 27 if ($fp === false) { 28 $errmsg = $file . "が開けません"; 29 return false; 30 } 31 if ($fp && flock($fp, LOCK_EX)) { 32 list($name, $age, $tel) = $data; 33 $insert = implode('<>', array($name, $age, $tel)) . "\n"; // $dataのままでもいいんじゃね? "\n"の連結の仕方をミスすると大変よ。 34 array_unshift($file_array, $insert); 35 rewind($fp); 36 ftruncate($fp, 0); 37 for ($i=0; $i < count($file_array); $i++) { 38 fwrite($fp, $file_array[$i]); 39 } 40 fclose($fp); 41 } 42 $errmsg = "登録しました。"; 43 return true; 44} 45

投稿2020/05/19 11:14

編集2020/05/19 12:18
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ファイル操作処理を一般化する関数

これ、どういった意味なんでしょうか?

中身はあまりちゃんと見ていませんが、一般化をするのであれば、まずはデータの構造を一般的なものにしてみては?

ファイルで扱うのであれば、csv, tsv あたりであれば、php での取り扱いが一般化(?)できます。

加工処理が頻発するのであれば、DB に突っ込むと良いです。排他処理の設計とかあまり気にしなくて良くなります。

投稿2020/05/19 12:56

編集2020/05/19 12:58
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/05/20 07:42

クラス設計しているわけでもないのだから、同じような処理を何度も書かない程度のリサイクルくらいの意味かな、って私は思ったけど、真意はわかりません。 データの格納や抽出は、早くデータベースを利用できるようにステップアップしていただきたいのは同意です。
guest

0

PHP

1foreach($file_array as $value){ 2//list($data) = explode('<>', $value); 3//この処理をどうすればよいか 4if($name == $list_name){ 5$flag = 1; 6} 7}

PHP

1foreach($file_array as $value){ 2 list($list_name,$list_age,$list_tel) = explode('<>', $value); 3 if($name == $list_name){ 4 $flag = 1; 5 } 6}

とするのと、
function func_regist($file , array $data , $check, $insert,$errmsg){
で引数を受け取っているのに
if($name == $list_name){
$nameという関数内では未定義の変数を使おうとしている事

  • $checkで引数を受け取っているのであれば、関数内で使用するときは$checkで使わないといけない

辺りが原因かと思います。(他にもあるかもしれませんが)

以下、コード修正前に必要なこと

以下は、開発をする上で必ず必要になることです。

エラーを表示させる
今回のケースだと、noticeが表示されていれば原因に気付けたと思います。
コードの最初に以下のコードを書いておき、全エラーを表示させてください(質問にも必ず記載する、質問前にそのエラーで検索する)

PHP

1ini_set("display_errors",1); 2ini_set("error_reporting",E_ALL);

IDEを使用する
これは私の手元のIDEですが、未定義の変数に赤線を付けてくれていることがわかるかと思います。
PHP IDE等で検索して、開発の補助をしてくれる開発環境を使用してください。
イメージ説明

インデントを整える
質問のコードのインデントが整っていないだけでコードを誤読しやすくなりますし、ミスも増えます。teratialにおいては回答者のモチベーションが限りなく下がります。
まともなIDEを使えばインデントを整えてくれる機能があるので、必ずインデントを整えてコードを書いてください。

問題個所の変数の中身を確認する
今回のケースだと

PHP

1var_dump($name); 2var_dump($list_name); 3if($name == $list_name){ 4

とすることで、$name$list_nameもnullであることがわかるので、そこから遡って行って$name$list_nameの発生個所が無いか、発生個所に問題があることが突き止められます。
IDEとxdebugを使ってブレークポイントを仕掛けるのが効率的ではありますが、まずはvar_dump()で変数の中身を確認するようにしてみてください。

投稿2020/05/19 09:28

編集2020/05/19 09:30
tanat

総合スコア18727

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

d__..___

2020/05/19 09:35

コメントありがとうございます!! $list_name,$list_age,$list_telを関数内に定義すると一般化ではなくなってしまうので、関数外から このデータを呼び出したいです。 一般化ができていれば $name = "山田次郎"; $sex = "男性"; $rank = "6"; $score = "80"; $file = "./score.dat"; 同じ関数で、このようなデーターも追加できるようにしたいです。 >function func_regist($file , array $data , $check, $insert,$errmsg){ >で引数を受け取っているのに >if($name == $list_name){ >と$nameという関数内では未定義の変数を使おうとしている事 失礼しました!ミスでした。
tanat

2020/05/19 09:53 編集

このチェックしている部分は 「与えられた名前がファイルの中に存在するかを確認する」 という処理なので、関数の中で展開するのが正しいところだと思いますよ。 ファイルパスは外から与えられているので、使い勝手も悪くは無いと思います。 「一般化では無くなってしまう」の基準が間違っているように思います。 「一般化」という用語自体が具体的なものでは無いので、 1.関数に与える引数は何か 2. 関数実行結果としてどうなれば正しいのか という関数の外部仕様(これをクリアしてればOK)を誰が読んでも判断出来るくらい厳密で具体的に書き出すと整理しやすいかと思います。
退会済みユーザー

退会済みユーザー

2020/05/19 11:23

文法エラーが有ると、ini_set()が通じなくなるので、php.iniに書くのが一番だと主張したいのコトヨ
tanat

2020/05/19 11:42

>m6uさん 補足ありがとうございます。 php.iniに書けるのであればそれがベストですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問