การเขียนฟังก์ชัน(Function)

อะไรเอ่ยเขียนครั้งเดียวแต่ใช้บ่อย?

ฟังก์ชันคืออะไร? ถ้าถามผม ผมบอกได้เลยว่ามันก็คือคำสั่งประเภทหนึ่งเท่านั้นเอง ใครทราบความหมายยาวๆบอกด้วย รู้แต่ใช้เท่านั้นเองแต่ที่แน่นๆมันทำให้ผู้ใช้ทำงานง่ายขึ้น แต่คนเขียนฟังก์ชันบางทีก็ไม่ง่ายนะครับ

ใน Visual FoxPro มีประเภทของฟังก์ชันอยู่ 2 ชนิดด้วยกัน
1. ฟังก์ชันที่มากับโปรแกรม (Visual FoxPro function)
2. ฟังก์ชันที่ผู้ใช้กำหนดเอง (user-defined function (UDF))

ฟังก์ชันที่มากับโปรแกรมนั้นมีอยู่มากพอสมควรแต่ยังไม่พอหรอกครับ เพราะนิสัยของมนุษย์มันไมรู้จักพออยู่แล้ว เขาก็เลยอนุญาติให้คุณๆทั้งหลายทำมันขึ้นมาได้เองจะทำเป็นอะไรก็ได้ไม่ว่ากันตามสบาย แต่ก็มีข้อแม้ในการทำบ้างเล็กๆน้อยๆ   หลักการทำฟังก์ชันขึ้นใช้เองก็ไม่ได้ยากเย็นเข็นใจอะไรมีข้อแม้ง่ายๆดังนี้
1. เวลาสร้างต้องเริ่มต้นด้วยคำว่า    FUNCTION แล้วก็ตามด้วยชื่อของฟังก์ชัน
2. ชื่อของฟังก์ชันยาวได้ไม่เกิน 254 ตัวอักษร ถ้าคุณใช้โปรแกรมที่ต่ำกว่า Visual FoxPro ใช้ได้แค่ 10 ตัว
3. ชื่อของฟังก์ชันต้องไม่ไปซ้ำกับชื่อของฟังก์ชัน และคำสั่งใน Visual FoxPro
4. ค่าส่งผ่าน (parameter) จะมีหรือไม่มีก็ได้ เท่าที่เห็นเค้าทำกันมีทั้งนั้นแหละ
5.   ค่าส่งผ่านมีได้สูงสุดใน 1 ฟังก์ชันไม่เกิน 24 ค่า
6. เมื่อเป็นฟังก์ชันเวลาออกต้องมีค่ากลับมาเสมอ ไม่ว่าจะเป็นตัวเลข ตัวอักษร ตรรกะ วันที่ หรือค่าที่ไม่มีค่า(NULL) เป็นต้น
7. เขียนได้ไม่จำกัดจำนวน ขยันก็เขียนไปมีแรงก็ทำไป เขียนจนตายก็ไม่จบ….ถ้ายังไม่รู้จักพอ

รู้หลักการทำไปแล้วมาดูหลักการใช้งานบ้าง
1. เราสามารถใช้ฟังก์ชันได้ทุกที่ที่เขียนเป็นนิพจน์คำสั่งได้ และฟังก์ชันของ Visual FoxPro ก็สามารถเขียนได้
2. สามารถเรียกฟังก์ชันซ้อนฟังก์ชันได้ถึง 32 ระดับ (ข้อมูลยังไม่แน่นอนตอนนี้อาจเยอะกว่านี้ก็ได้ แต่ยังไม่เคยเห็นใครเขียนเยอะขนาน 32 ระดับเลย)

ทีนี้เรามาดูตัวอย่างการใช้กันก่อน (ขอยืมของ ฟังก์ชันในVisual FoxPro ใช้ก่อนก็แล้วกัน)
myVAR = DATE()
STOR MONTH(DATE()) TO thisMonth
=CAPSLOCK(.T.)    && กำหนดให้ป้อนข้อมูลเป็นตัวอักษรใหญ่
DO WHILE !EOF()
INSERT INTO Salesman(LASTUPDATE) VALUE(DATE())

จากตัวอย่างข้างต้นเราจะสังเกตุได้อย่างไรว่าอะไรเป็นฟังก์ชัน ง่ายๆก็คือหลังคำสั่งนั้นๆจะมีวงเล็บ() อยู่ แต่อย่างงละว่า Salesman เป็นฟังก์ชั่นเพราะมีวงเล็บ มันคนละเรื่องกันอันนั้นมันเป็น คีย์เวิร์ดของคำสั่ง INSERT INTO

เรามาเริ่มเขียนฟังก์ชันใช้กันดีกว่า
เริ่มง่ายๆลองป้อนโปรแกรมตามตัวอย่างข้างล่างก่อนเป็นการนำ ฟังก์ชันของ Visual FoxPro มาดัดแปลงให้เป็นตามแบบที่เราต้องการเพื่อความสะดวกของเราเอง

ให้สร้างโปรแกรมชื่อ UTILITY.PRG จาก command windows ป้อน modify command UTILITY แล้วพิมพ์คำสั่งตามตัวอย่างด้านล่างลงไป

FUNCTION MyMessage
PARAMETER cMessageText,cMessageTitle
* 4 = Yes and No buttons
* 32 = Question mark icon
* 256 = Secound buttons is default
* return value 6 for click YES
* return value 7 for click NO
RETURN MESSAGEBOX(cMessageText,4+32+256,cMessageTitle)

เวลาเราทำการเรียกใช้ฟังก์ชัน ให้คุณทำการป้อนคำสั่ง SET PROCEDURE TO UTILITY เพื่อบอกให้โปรแกรมทำการหาฟังก์ชันจาก โปรแกรมที่เรากำหนดไว้ก็คือโปรแกรม UTILITY หลังจากนั้นเราลองทำการทดสอบฟังก์ชันของเราดู ให้ป้อนคำสั่งต่อไปนี้ที่ command windows ดูว่าเกิดอะไรขึ้นบ้าง

? MyMessage(‘ต้องการบันทึกข้อมูล’,’บันทึกข้อมูล’)
nAnswer = MyMessage(‘ต้องการบันทึกข้อมูล’,’บันทึกข้อมูล’)
?nAnswer

ท่านทราบหรือไม่ว่าเมื่อเราทำการเรียกใช้งานฟังก์ชันใน Visual FoxPro มีลำดับการค้นหาว่าฟังก์ชันที่เราเรียกใช้งานนั้นอย่างไร
ลำดับแรกเลยถ้าเรามีการเรียกใช้งานฟังก์ชันใดๆก็ตามโปรแกรมจะทำการหาที่ฟังก์ชันของ Visual FoxPro ก่อน
ลำดับถัดมาโปรแกรมจะทำการหาที่ โพซิเยอร์(Procedure) ที่เราทำการเปิดอยู่   เราเปิดโดยใช้คำสั่ง set procedure to ….
สุดท้ายถ้าหาทั้งสองที่ไม่เจอก็จะทำการหาที่ โปรแกรม .prg เช่น เรียกใช้ฟังก์ชัน MyMessage ก็จะทำการหาว่ามีโปรแกรมชื่อ MyMessage.prg หรือไม่ ถ้ามีก็เรียกใช้งานให้
ถ้ายังหาไม่เจออีกก็จะขึ้น Error ว่า File ‘????????.prg’ does not exist

ในการเขียนฟังก์ชันขึ้นมานั้น เมื่อเราเขียนเสร็จเรียบร้อยแล้วเราควรจะทำการเก็บเป็นหมวดหมู่หรือ Library ไว้ เวลาเรียกใช้งานหรือนำไปใช้งานจะได้สะดวก แล้วจะทำอย่างไรล่ะ? จากตัวอย่างข้างต้นผมให้สร้างโปรแกรมชื่อ utility.prg ขึ้นมาเพื่อทำการเก็บ ฟังก์ชันที่เราได้ทำการเขียนขึ้นมา ใน 1 โปรแกรมเราสามารถใส่ฟังก์ชันที่เราเขียนขึ้นมาได้เรื่อยๆขึ้นอยู่กับ memory ของเครื่องคุณว่าจะรับได้แค่ไหน โดยการเขียนต่อๆกันไปเรื่อยๆ ดังนี้

*    utility.prg
FUNCTION MyMessage
……
RETURN <value>

FUNCTION tCDOW
PARAMETER dDATE
nDay=DOW(dDATE)
DO CASE
CASE nDAY=1
RETRUN ‘อาทิตย์’
CASE nDAY=2
RETRUN ‘จันทร์’
CASE nDAY=3
RETRUN ‘อังคาร’
CASE nDAY=4
RETRUN ‘พุธ’
CASE nDAY=5
RETRUN ‘พฤหัสบดี’
CASE nDAY=6
RETRUN ‘ศุกร์’
CASE nDAY=7
RETRUN ‘เสาร์’
ENDCASE
RETURN ”

FUNCTION myFunction
……
RETURN

…..

เมื่อเราทำการเขียนโปรแกรมที่ทำการเก็บฟังก์ชันต่างๆแล้ว เวลาจะนำมาใช้งานเราต้องประกาศให้ Visual FoxPro ทราบก่อน โดยใช้คำสั่ง set procedure to ซึ่งเคยยกตัวอย่างไว้ให้ดูแล้วในตอนต้นทีนี้เรามาดูรูปแบบคำสั่งว่าเป็นอย่างไร

SET PROCEDURE TO [FileName1 [, FileName2, …]]    [ADDITIVE]

เช่น       SET PROCEDURE TO UTILITY,MYFUNCTION,STATFUNCTION
SET PROCEDURE TO FORMFUNCTION ADDITIVE

ส่วนใหญ่การประกาศใช้ฟังก์ชันเราจะกระทำกันที่ main program ประกาศไว้ครั้งแรกครั้งเดียวก็พอ

ต่อไปนี้เป็นต้วอย่างฟังก์ชัน
ถ้าคุณมีฟังก์ชันที่ดีๆแล้วต้องการเผยแพร่กรุณาส่งมาหาเราเราจะเป็นสื่อกลางให้

Download NUM2CH.PRG
* —FUNCTION NUM2CH
* —โปรแกรม…… เปลื่ยนตัวเลขเป็นตัวอักษร (9,999,999,999.99)
* —ผู้เขียน…….. Kasem K.
* —วันแก้ไข……. 12.08.92
*– นำไปใช้…… cSTRING=NUM2CH(9999.22)
***************************************************************
FUNCTION NUM2CH
PARA mNUM && เลขไม่เกิน 10.2 หลัก
PUBL mTCH(9),mTDEC(10)
mTCH(1)=’หนึ่ง’
mTCH(2)=’สอง’
mTCH(3)=’สาม’
mTCH(4)=’สี่’
mTCH(5)=’ห้า’
mTCH(6)=’หก’
mTCH(7)=’เจ็ด’
mTCH(8)=’แปด’
mTCH(9)=’เก้า’
mTDEC(1) =’พัน’
mTDEC(2) =’ร้อย’
mTDEC(3) =’สิบ’
mTDEC(4) =’ล้าน’
mTDEC(5) =’แสน’
mTDEC(6) =’หมื่น’
mTDEC(7) =’พัน’
mTDEC(8) =’ร้อย’
mTDEC(9) =’สิบ’
mTDEC(10)=”
mSTNUM=STR(mNUM*100,12)
mSTTHAI=”
mCNT=1
DO WHIL mCNT<=10
mCHNUM=SUBSTR(mSTNUM,mCNT,1)
IF mCHNUM=’ ‘
mSTTHAI=mSTTHAI+”
ELSE
IF mCHNUM=’0′
mSTTHAI=IIF(mCNT=4,mSTTHAI+’ล้าน’,mSTTHAI+”)
ELSE
IF mCHNUM=’1′
IF (mCNT=4.AND.LEN(LTRIM(mSTNUM))#9).OR.(mCNT=10.AND.LEN(LTRIM(mSTNUM))#3)
mSTTHAI=mSTTHAI+’เอ็ด’
ELSE
IF .NOT.(mCNT=3.OR.mCNT=9)
mSTTHAI=mSTTHAI+mTCH(VAL(mCHNUM))
ENDIF
ENDIF
ELSE
IF mCHNUM=’2′.AND.(mCNT=3.OR.mCNT=9)
mSTTHAI=mSTTHAI+’ยี่’
ELSE
mSTTHAI=mSTTHAI+mTCH(VAL(mCHNUM))
ENDIF
ENDIF
mSTTHAI=mSTTHAI+mTDEC(mCNT)
ENDIF
ENDIF
mCNT=mCNT+1
ENDDO
mSTTHAI=mSTTHAI+’บาท’
IF SUBSTR(mSTNUM,11,2)=’00’
mSTTHAI=mSTTHAI+’ถ้วน’
ELSE
mCHNUM=SUBSTR(mSTNUM,11,1)
IF mCHNUM#’0′
IF mCHNUM#’1′
IF mCHNUM=’2′
mSTTHAI=mSTTHAI+’ยี่’
ELSE
mSTTHAI=mSTTHAI+mTCH(VAL(mCHNUM))
ENDIF
ENDIF
mSTTHAI=mSTTHAI+mTDEC(9)
ENDIF
mCHNUM=SUBSTR(mSTNUM,12,1)
IF mCHNUM#’0′
IF mCHNUM=’1′.AND.SUBSTR(mSTNUM,11,1)#’0′
mSTTHAI=mSTTHAI+’เอ็ด’
ELSE
mSTTHAI=mSTTHAI+mTCH(VAL(mCHNUM))
ENDIF
ENDIF
mSTTHAI=mSTTHAI+’สตางค์’
ENDIF
RETU mSTTHAI

* —TSCDOW.PRG
* —ผู้เขียน…….. Kasem K.
* —วันแก้ไข……. 12.08.92
*– นำไปใช้…… cDayofWeek=TSCDOW(DATE())
* —โปรแกรม…. ROUTINE ให้ค่าชื่อวันไทยแบบย่อ
FUNCTION TSCDOW
PARA mdtm
mdtnm=DOW(mdtm)
mcdm=SUBST(‘อาจ.อ.พ.พฤศ.ส.’,2*mdtnm-1,2)
RETU (mcdm)

*—————————————-
* โปรแกรม : MLOGIC.PRG
* เขี่ยโดย : พณฯ เกษม
* สร้าง : 01/09/92
* มันคือ : GAME ใช้ฝึกสมอง มนุษย์เหล็ก 2022
* สัญลักษณ์ : C=ถูกสี , P = ถูกตำแหน่ง
*—————————————-
PROCEDURE MLOGIC
DECL S(5),X(5)
DEFI WIND MLOGIC FROM 1,10 TO 21,45;
TITLE “MASTER LOGIC” FOOT “ESC – EXIT”;
GROW SYSTEM ZOOM COLO N/BG,N/BR,B+/W
ACTI WIND MLOGIC
DO WHIL .T.
CLEA
STOR .F. TO FLAG
STOR 0 TO S(1),S(2),S(3),S(4),S(5)
STOR 0 TO L,POSI,COLF
STOR 0 TO SCORE
STOR ” TO Q_A
@0,1 SAY ‘SELECT : ‘ COLO 5+/3
@2,0 SAY ‘C P’ COLO 2+/3
@2,4 TO 2,22
@0,24 TO 9,32
@1,25 SAY ‘LEGENT’ COLO 6+/3
@2,25 SAY ‘1’
@2,28 SAY ‘ ‘ COLO /1
@3,25 SAY ‘2’
@3,28 SAY ‘ ‘ COLO /2
@4,25 SAY ‘3’
@4,28 SAY ‘ ‘ COLO /3
@5,25 SAY ‘4’
@5,28 SAY ‘ ‘ COLO /4
@6,25 SAY ‘5’
@6,28 SAY ‘ ‘ COLO /5
@7,25 SAY ‘6’
@7,28 SAY ‘ ‘ COLO /6
@8,25 SAY ‘7’
@8,28 SAY ‘ ‘ COLO /7
@10,24 TO 13,32
@11,25 SAY ‘SCORE’
DO WHIL SCORE < 15
IF SCORE=0
FOR I = 1 TO 5
STOR STR(INT(RAN(1,8)),1) TO X(I)
Q_A=Q_A+X(I)
NEXT
@ 3,0 SAY ‘=>’ COLO 0/3
ELSE
@ 3+SCORE-1,1 SAY ‘ ‘
@ 3+SCORE,0 SAY ‘=>’ COLO 0/3
ENDIF
@1, 6 GET S(1) PICT’@Z 9′ RANG 1,7 COLO ,7+;
VALID(SAYCOL(S(1),1,6) .AND.SAYCOL(S(1),3+L,6 ))
@1,10 GET S(2) PICT’@Z 9′ RANG 1,7 COLO ,7+;
VALID(SAYCOL(S(2),1,10).AND.SAYCOL(S(2),3+L,10))
@1,14 GET S(3) PICT’@Z 9′ RANG 1,7 COLO ,7+;
VALID(SAYCOL(S(3),1,14).AND.SAYCOL(S(3),3+L,14))
@1,18 GET S(4) PICT’@Z 9′ RANG 1,7 COLO ,7+;
VALID(SAYCOL(S(4),1,18).AND.SAYCOL(S(4),3+L,18))
@1,22 GET S(5) PICT’@Z 9′ RANG 1,7 COLO ,7+;
VALID(SAYCOL(S(5),1,22).AND.SAYCOL(S(5),3+L,22))
READ
mKEY=READK()
DO CASE
CASE mKEY=12.OR.mKEY=268
FLAG=.T.
EXIT
ENDCASE
* PROCESS
STOR 0 TO POSI,COLF
FOR I = 1 TO 5
IF STR(S(I),1)=X(I)
POSI=POSI+1
ENDIF
IF STR(S(I),1)$Q_A
COLF=COLF+1
ENDIF
NEXT
IF POSI=5
SCORE=SCORE+1
@ 12,27 SAY SCORE PICT ‘@Z 99’
TEMP=WARNN(‘ YOU HAVE A WINNER ! ‘,10)
EXIT
ENDIF
* END PROCESS
SCORE = SCORE+1
@ 3+L,0 SAY COLF PICT ‘9’ &&COLO 7+/3
@ 3+L,2 SAY POSI PICT ‘9’ &&COLO 7+/3
@ 12,27 SAY SCORE PICT ‘@Z 99’
L = L +1
ENDDO
IF FLAG
EXIT
ENDIF
IF POSI#5
DEFI WIND IWIN FROM 7,1 TO 12,29;
TITLE “o REPLY BOX o” GROW SYSTEM ZOOM COLO N/N,N/BR,B+/W
ACTI WIND IWIN
@0,1 TO 4,25
@1, 4 SAY ‘ ‘+X(1)+’ ‘ COLO 7+/&X(1)
@1, 8 SAY ‘ ‘+X(2)+’ ‘ COLO 7+/&X(2)
@1,12 SAY ‘ ‘+X(3)+’ ‘ COLO 7+/&X(3)
@1,16 SAY ‘ ‘+X(4)+’ ‘ COLO 7+/&X(4)
@1,20 SAY ‘ ‘+X(5)+’ ‘ COLO 7+/&X(5)
@2, 4 SAY ‘ ‘ COLO /&X(1)
@2, 8 SAY ‘ ‘ COLO /&X(2)
@2,12 SAY ‘ ‘ COLO /&X(3)
@2,16 SAY ‘ ‘ COLO /&X(4)
@2,20 SAY ‘ ‘ COLO /&X(5)
TEMP=WARNN(‘ I WINNER !!! ‘,10)
RELE WIND IWIN
ENDIF
ENDDO
RELE WIND MLOGIC
RETU

FUNCTION SAYCOL
PARA SEL,ROW,COLX
CSEL=STR(SEL,1)
@ROW,COLX-2 SAY ‘ ‘+CSEL COLO &CSEL+/&CSEL,/&CSEL
RETU .T.

* —RAN.PRG
* —ผู้เขียน…… Kasem K.
* —แก้ไขล่าสุด… 17/09/92
* —โปรแกรม…. รูทีนสร้างตัวเลขสุ่มระหว่างช่วง
FUNCTION RAN
PARA RA,RB
RETU (RB-RA)*RAND()+RA

*!*********************************************************************
*!
*! Procedure: WARNN
*!
*!*********************************************************************
PROCEDURE warnn
PARA mmsg,mtime
*SET COLO OF SCHE 9 TO N/BG,N/RB,RG/W
mlen=lcut(mmsg)
mmsg=’ ‘+REPL(‘ ‘,LEN(mmsg)-mlen)+mmsg+’ ’
DEFI WIND warnn FROM 19,4 TO 21,LEN(mmsg)+5 SYST ;
SHAD FLOAT NOZOOM COLO SCHE 9
ACTI WIND warnn
*@23,40-(mLEN/2) SAY mMSG
@0,0 SAY mmsg
??CHR(7)
i=INKEY(mtime)
*@23,40-(mLEN/2) SAY SPAC(LEN(mMSG))
RELE WIND warnn
RETU

&& ถ้าคุณมีปัญหาเกี่ยวกับการจัดเรียงข้อมูลภาษาไทยต้องอันนี้

Download ITHAI.PRG
* —ITHAI.PRG
* —แก้ไขล่าสุด… 06/02/35
* —โปรแกรม…. ROUTINE FUNCTION INDEX THAI LANGUAGE
* การใช้งานนั้นใช้ตอน index on ithai(name) tag sortthai  && ถ้าข้อมูลเยอะๆช้าครับ
* ขอแนะนำให้ทำการสร้าง filed เพิ่มอีก 1 ฟิลด์สมมุติชื่อ sortname   ตอนปรับปรุงฟิลด์นั้นให้เพิ่มคำสั่ง
*        REPLACE SORTNAME WITH ITHAI(NAME) วิธีนี้คุณสามารถนำฟิลด์ไปใช้ในคำสั่ง SQL ได้ด้วย
FUNCTION ithai
PARA str0
mstr=TRIM(str0)+’ ‘
mlen=LEN(mstr)
IF mlen<=1
RETU mstr
ENDIF
mcnt=1
DO WHIL mcnt<=mlen
mchr=SUBSTR(mstr,mcnt,1)
IF mchr$’เแโไใ’
mstr=LEFT(mstr,mcnt-1)+SUBSTR(mstr,mcnt+1,1)+SUBSTR(mstr,mcnt,1)+RIGHT(mstr,mlen-(mcnt+1))
mcnt=mcnt+1
ENDIF
mcnt=mcnt+1
ENDDO
mcnt=1
DO WHIL mcnt<=mlen
mchr=SUBSTR(mstr,mcnt,1)
IF mchr$’่้๊๋็’
mstr=LEFT(mstr,mcnt-1)+SUBSTR(mstr,mcnt+1,1)+SUBSTR(mstr,mcnt,1)+RIGHT(mstr,mlen-(mcnt+1))
mcnt=mcnt+1
ENDIF
mcnt=mcnt+1
ENDDO
RETU mstr

* —LCUT.PRG
* —แก้ไขล่าสุด… 02/09/34
* —โปรแกรม…. ROUTINE นับความยาวโดยตัดอักขระบนล่าง
*!*********************************************************************
*!
*! Procedure: LCUT
*!
*!*********************************************************************
FUNCTION lcut
PARA mstr
cnt0 = 1
cnt00 = 0
DO WHIL cnt0 <= LEN(mstr)
IF SUBS(mstr,cnt0,1) $ ‘ุูิีึืั์่้๊๋็’
cnt00 = cnt00 + 1
ENDIF
cnt0 = cnt0 + 1
ENDDO
RETU (LEN(mstr) – cnt00)

*!*********************************************************************
*!
*! Procedure: STIFF
*!
*!*********************************************************************
FUNCTION stiff
PARA ma,mb
mb=TRIM(LTRIM(mb))
mt=LEFT(ma,LEN(ma)-LEN(mb))+mb
RETU mt