article

توابع (Functions) در PHP

php-function

از جمله مباحثی که در اغلب زبان های برنامه نویسی به چشم می خورد مبحث توابع (Functions) است، برنامه نویسان همواره در پی یافتن سریعترین راه حل ها با کمترین کدنویسی و در عین حال رسیدن به مقصودشان به بهینه ترین شکل ممکن هستند و به همین خاطر است که به جای نوشتن چندین و چندباره دستورات، یک بار کدها را به صورت توابع تعریف کرده و بعد از آن در هر بار فراخوانی به تابع ورودی داده و خروجی مد نظرشان را دریافت می کنند، در واقع توابع نقش ماشین های تسهیل کننده را برای برنامه های مختلف بازی می کنند که به کمک آنها می توانیم یک سری از پردازش ها را چندین و چند بار داشته باشیم بدون اینکه بخواهیم برای هر پردازش کدها را جداگانه تعریف کنیم، با این مقدمه کوتاه می پردازیم به ادامه آموزش برنامه نویسی PHP با مبحث توابع (Functions).

تابع (Function) چیست و چه کاربردی دارد؟


در زبان های برنامه نویسی و از جمله در PHP توابع ماشین هایی با ساختار از قبل تعریف شده (بلاکی از کدها) هستند که معمولا با دریافت مقدار یا مقادیری به عنوان ورودی پردازش های مد نظر برنامه نویس را انجام داده و در نهایت حاصل این پردازش ها به عنوان خروجی در ادامه برنامه قابل استفاده است، به این دلیل به تابع "ماشین" می گوییم چون مانند یک دستگاه مواد خام را دریافت کرده و در نهایت محصول تولید می کند و به همین جهت روندهای تکراری با نوشتن یک تابع چندین و چند بار در برنامه قابل انجام است، همچنین به این دلیل گفتیم "معمولا با دریافت مقدار یا مقادیر ورودی" چون در دنیای برنامه نویسی توابع را بدون مقدار ورودی هم می توانیم استفاده کنیم و حتی برخی توابع هیچ مقدار ورودی یا خروجی ندارند و صرفا تغییراتی در متغیرها و آبجکت ها ایجاد می کنند که همه اینها بستگی به نیاز برنامه ما دارد.

انواع مختلف تابع در PHP


در یک تقسیم بندی کلی توابع در PHP به دو صورت زیر قابل تفکیک هستند:
- توابع درونی یا از پیش تعریف شده (Predefined یا Internal (built-in) functions).
- توابع سفارشی یا تعریف شده توسط کاربر (Custom یا User-defined functions).
منظور از توابع درونی مواردی هستند که به صورت ذاتی در مفسر PHP وجود دارند و به کمک آنها می توانیم بدون نوشتن کدهای اضافه با سرعت و سهولت بیشتری روند توسعه برنامه ها را پیش ببریم، به طور مثال تابع str_replace برای جایگزینی مقادیر رشته ای با هم، تابع is_numeric برای بررسی عدد بودن یک مقدار، تابع strtolower برای تبدیل حروف بزرگ انگلیسی به شکل حروف کوچک و موارد فراوانی از این دست که در مفسر PHP از قبل تعریف شده و به همراه هسته برنامه نصب می شوند.
علاوه بر توابع درونی این قابلیت در زبان PHP وجود دارد که تابع سفارشی و شخصی تعریف کنیم، توابع شخصی معمولا با هدف اجرای بلاکی از کدها به دفعات متعدد در قسمت های مختلف برنامه نوشته می شوند و با این کار روندهای مشابه با یک بار کدنویسی چندین و چند بار قابل تکرار هستند، برای نوشتن و استفاده از توابع سفارشی باید قواعد زبان PHP را رعایت کنیم.
در ادامه آموزش ابتدا توابع سفارشی را بررسی و سپس اشاره ای به توابع درونی PHP خواهیم کرد.

شیوه نگارش (Syntax) تعریف تابع در PHP


شیوه نگارش (Syntax) تعریف توابع در PHP شباهت زیادی به دیگر زبان پرکاربرد وب یعنی جاوا اسکریپت دارد، در PHP هم برای تعریف تابع از عبارت function با نمونه فرمت زیر استفاده می کنیم:
<?php
//تعریف تابع
function boldMyText($text){
    $result = '<strong>' . $text . '</strong>';
    return $result;
}
?>
توضیح:
- توابع در PHP با عبارت function و درج نام با شرایطی که در ادامه خواهیم گفت تعریف می شوند، در قسمت () آرگیومنت ها یا همان ورودی های تابع تنظیم می شود و قسمت {} بدنه اصلی و کدهایی که باید تابع اجرا کند را دربر می گیرد، در نهایت نیز معمولا حاصل فرآیند تابع با عبارت دستوری return برگردانده می شود.
- استفاده از آرگیومنت و return در توابع اختیاری است، به عبارتی می توانیم توابعی بدون ورودی یا خروجی داشته باشیم (به فرض تابع صرفا مقدار یک متغیر یا آبجکت را در روند برنامه تغییر دهد).

قواعد نامگذاری توابع در PHP


مانند هر زبان برنامه نویسی PHP نیز از قواعد خاصی برای نامگذاری توابع پیروی می کند، در PHP نام توابعی که تعریف می کنیم می تواند در چارچوب Regex زیر عبارتی دلخواه شامل حروف و اعداد انگلیسی، کاراکتر زیرخط یا Underline "_" یا کاراکترهای non-ASCII (کاراکترهای خارج از استاندارد ASCII) باشد:
^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$
اطلاعات بیشتر در خصوص استاندارد ASCII:
asciitable.com
شروع نامگذاری تابع حتما باید با حروف یا کاراکتر _ باشد، جالب است که با توجه به پشتیبانی از یونیکد UTF-8 (عبارت زیر در دستور باقاعده بالا کاراکترهای non-ASCII را شامل می شود:)
\x80-\xff
استفاده از نام و اعداد فارسی برای تابع در PHP ممکن است، در مجموع توصیه می کنیم برای سازگاری و خواناتر شدن کدها در نامگذاری عموما از کلمات با معنی به صورت تکی یا در ترکیب با سایر کلمات و اعداد انگلیسی استفاده کنیم، به طور مثال چند نام فرضی برای توابع:
clean, changeUser, getNewResult, textType1, textType2, getParam_1, getParam_2
انتخاب نام به صورت صرفا عددی (به فرض 01234) یا دارای کارکترهای خاص (به فرض ^ * #) مجاز نیست و در صورت استفاده خطای مشابه زیر را دریافت خواهیم کرد:
Parse error: syntax error, unexpected '1' (T_LNUMBER), expecting identifier (T_STRING) or '(' in ... .php on line 2

فراخوانی توابع در PHP


برای اینکه توابع در کدها اثرگذار باشند حتما باید آنها را فراخوانی (Call) کنیم، فراخوانی توابع در کدهای PHP معمولا به صورت استفاده مستقیم و بی واسطه است با این حال به فراخور نیاز برنامه ها شیوه های دیگری نیز برای فراخوانی توابع وجود دارد که در ادامه بررسی می کنیم.
- فراخوانی تابع به صورت مستقیم
در این شیوه بسته به هدف یا خروجی که تابع بر می گرداند (رشته، عدد، مقادیر بولین و...) می توانیم از تابع به صورت مستقیم استفاده کنیم، به طور مثال نمونه کد زیر خروجی تابع را که یک رشته متنی است با دستور echo چاپ می کند:
<?php
//تعریف تابع
function boldMyText($text){
    $result = '<strong>' . $text . '</strong>';
    return $result;
}
//متغیر
$text = "این متن را برجسته کن";
//فراخوانی تابع
echo boldMyText($text);
?>
با اجرای این نمونه کد در لوکال هاست یا سرور آنلاین مقادیر متغیر text به صورت برجسته شده با تگ strong در خروجی صفحه چاپ می شود.
مثال دیگر از به کار بردن مستقیم تابع در PHP:
<?php
function checkOddEven($number){
    if($number % 2 == 0){
        return true;  
    }

    return false;
}
if(checkOddEven(2)){
    echo 'عدد زوج است';
} else {
    echo 'عدد فرد است';
}
?>
این تابع زوج یا فرد بودن عدد دریافتی را بررسی و مقادیر true یا false را به عنوان نتیجه برمی گرداند.
- اختصاص تابع به متغیر و فراخوانی با واسطه
در این شیوه ابتدا تابع را به روال متداول تعریف می کنیم و سپس برای فراخوانی نام تابع را به متغیر نسبت داده و در ادامه ی کدها متغیر را با پارامترهای مد نظرمان فراخوانی می کنیم، مثال:
<?php
function myFuncName($arg_1, $arg_2){
    if(!is_numeric($arg_1) || !is_numeric($arg_2)){
        return false;
    }
    
    return $arg_1 + $arg_2;
}
$my_var = "myFuncName";
echo $my_var(2, 4);
?>
خروجی نمونه کد بالا عدد 6 خواهد بود.
- استفاده از تابع درونی call_user_func
شیوه دیگری که PHP برای فراخوانی توابع در اختیارمان قرار می دهد استفاده از متغیر و تابع درونی call_user_func است، به طور مثال:
<?php
function myFuncName($arg_1, $arg_2){
    if(!is_numeric($arg_1) || !is_numeric($arg_2)){
        return false;
    }
    
    return $arg_1 + $arg_2;
}
$var = call_user_func("myFuncName", 2, 4);
echo $var;
?>
خروجی نمونه کد بالا عدد 6 خواهد بود.
- استفاده از تابع eval (توصیه نمی شود)
این امکان در مفسر PHP وجود دارد که یک رشته را به صورت کدهای PHP پردازش و اجرا کنیم، برای این کار تابع درونی eval کاربرد دارد، مثال:
<?php
function myFuncName($arg_1, $arg_2){
    if(!is_numeric($arg_1) || !is_numeric($arg_2)){
        return false;
    }
    
    return $arg_1 + $arg_2;
}
$var = "echo myFuncName(2, 4);";
eval($var);
?>
خروجی نمونه کد بالا عدد 6 خواهد بود.
نکته: استفاده از تابع eval به لحاظ امنیت برنامه ممکن است با خطراتی همراه باشد و بخصوص اگر قرار است که ورودی از سمت کاربر در این تابع اجرا شود باید حتما قبلا رشته ارسالی کاملا اعتبارسنجی و ایمن سازی شود.

آرگیومنت (Argument) تابع


در برنامه نویسی با زبان PHP استفاده از توابع می تواند با و بدون ورودی باشد اما معمولا توابع را با یک یا چند ورودی (جدا شده با علامت کاما ",") تعریف و به این ورودی ها در اصطلاح آرگیومنت (Argument) می گوییم، در هنگام تعریف و فراخوانی تابع بسته به هدف و نوع پردازش های مد نظر آرگیومنت ها می توانند به یکی از صورت های زیر باشند:
- فراخوانی با مقدار (Call by Value)
این حالت شیوه پیش فرض استفاده از آرگیومنت برای توابع در PHP است، در این شیوه پارامتر یا پارامترهای مد نظر به صورت متغیر بین کاراکترهای () تعریف و در هنگام فراخوانی به صورت مستقیم یا به شکل متغیر مقداردهی می شوند، مثال:
<?php
function checkValueExist($value, $array){
    if(in_array($value, $array)){
        return true;
    }
    
    return false;
}

$array = Array('A', 'E', 'G');
$value = 'R';

if(checkValueExist($value, $array)){
    echo 'مقدار ' . $value . ' در آرایه وجود دارد';
} else{
    echo 'مقدار ' . $value . ' در آرایه وجود ندارد';
}
?>
در این نمونه کد تابع فرضی checkValueExist با دو آرگیومنت تعریف شده است که پارامتر اول (value) می تواند یک رشته متنی و پارامتر دوم (array) یک آرایه باشد (در خصوص آرایه ها در مباحث آینده مفصل خواهیم گفت)، تابع مقادیر ورودی را دریافت کرده و وجود پارامتر اول را در آرایه دریافتی بررسی و در نهایت با مقادیر true یا false نتیجه را برمی گرداند و بر این مبنا می توانیم در دستور شرطی if تصمیم بگیریم که کدام قسمت از کدها اجرا شوند.
- فراخوانی با ارجاع (Call by Reference)
در حالت معمول پردازش های صورت گرفته بر مقادیر ورودی در روند تابع روی متغیرهای بیرون از تابع تاثیری ندارند، به طور مثال متغیر فرضی a در نمونه کد زیر همیشه مقدار 5  را چاپ می کند:
<?php
function doIncrement($num){
    return $num++;
}
$a = 5;
doIncrement($a);
echo $a;
?>
اما با استفاده از کاراکتر & می توانیم این حالت را تغییر داده و اثر تابع را بر روی متغیر بیرون از آن داشته باشیم، مثال:
<?php
function doIncrement(&$num){
    return $num++;
}
$a = 5;
doIncrement($a);
echo $a;
?>
خروجی این نمونه کد عدد 6 خواهد بود.
به این شیوه تعریف آرگویمنت ها با استفاده از کاراکتر &، فراخوانی با ارجاع یا Call by Reference می گوییم.
- مقادیر پیش فرض آرگیومنت ها (Default argument values)
شکل دیگر استفاده از آرگیومنت ها برای توابع تعریف آنها با مقادیر پیش فرض است، به این صورت اگر تابع را بدون آرگیومنت فراخوانی کنیم مقادیر پیش فرض جایگزین آرگیومنت می شود، مثال:
<?php
function sayWelcome($user = "Admin"){
    echo "Hi " . $user . ", Welcome to Control Panel!<br>";
}
sayWelcome();
sayWelcome("Manager");
?>
در صورت اجرای نمونه کد بالا در لوکال یا سرور خروجی زیر چاپ خواهد شد:
Hi Admin, Welcome to Control Panel!
Hi Manager, Welcome to Control Panel!
گفتیم توابع را بدون return هم می توانیم استفاده کنیم.
- لیست آرگیومنت ها با طول متغیر (Variable-length argument list)
شیوه جالب دیگر استفاده از آرگیومنت برای توابع که در PHP نسخه 5.6 و مابعد اضافه شده استفاده از عملگر سه نقطه (Splat یا Three dots Operator) و تنظیم ورودی به صورت لیست با طول متغیر است، در این شیوه تعداد آرگیومنت ها از قبل مشخص نیست و بسته به نیاز می تواند میزانی متغیر باشد، به طور مثال (کد صرفا در PHP نسخه 5.6 و مابعد قابل اجرا است):
<?php
function addNumbers(...$number){
    $result = 0;
    
    foreach($number as $key => $value){
        $result += $value;       
    }
    
    return $result;
}

echo addNumbers(1, 5, 6);
?>
خروجی نمونه کد بالا عدد 12 خواهد بود.
همان طور که مشخص است در این شیوه آرگیومنت به همراه کاراکتر سه نقطه تعریف شده و در تابع به شکل آرایه در حلقه foreach از آن استفاده کرده ایم، این شکل از استفاده از سه نقطه جهت دستیابی به مقادیر آرگیومنت را در اصطلح برنامه نویسی شیوه دسترسی به آرگیومنت های متغیر (Accessing Variable Arguments Method) می گوییم.
از سه نقطه در هنگام فراخوانی تابع هم می توانیم برای استخراج (Unpack) آرایه (یا متغیرهای Traversable یا Literal) و اختصاص به مقادیر آرگیومنت ها استفاده کنیم، البته در این حالت باید تعداد پارامترهای تابع مشخص باشد، مثال (کد صرفا در PHP نسخه 5.6 و مابعد قابل اجرا است):
<?php
function addNumbers($a, $b, $c){
    $result = $a + $b + $c;
    
    return $result;
}
$var = [1, 5, 6];
echo addNumbers(...$var);
?>
خروجی این نمونه کد هم مقادیر 12 خواهد بود.
به این شکل استفاده از سه نقطه جهت اختصاص مقادیر آرگیومنت ها را در اصطلاح برنامه نویسی شیوه مقداردهی به آرگیومنت های متغیر (Providing Variable Arguments Method) می گوییم.
نکته: مفاهیم Traversable یا Literal اصطلاحات تخصصی برنامه نویسی هستند که آموزش آنها در مرحله مقدماتی مورد نیاز نیست و در عمل هم شاید صرف این مفاهیم به خودی خود خیلی کاربردی نباشند، در همین حد بدانیم که یکی از کاربردهای کاراکتر سه نقطه می تواند با این نوع متغیرها باشد کافی است.
آخرین شکل استفاده از لیست آرگیومنت ها با طول متغیر شیوه استفاده با اشاره به نوع ورودی (Type hinted Variable Arguments Method) است، در این شیوه نام یک کلاس با فاصله قبل از کاراکتر ... قرار می گیرد و در این صورت ورودی ها الزاما باید نمونه (Instance) ای از آن کلاس باشند و در نهایت می توانیم به آبجکت های public آن کلاس در تابع دسترسی داشته باشیم، مثال:
<?php
class MyClass{
    private $var_1 = 5;
    private $var_2 = 8;
    public $myInt;
    
    function __construct($type){
        switch($type){
            case 'a':
                $this->myInt = $this->var_1;
            break;
            case 'b':
                $this->myInt = $this->var_2;
            break;
        }
    }
}

function addNumbers(MyClass ...$number){
    $result = 0;
    
    foreach($number as $key => $value){
        $result += $value->myInt;
    }
    
    return $result;
}

$a = new MyClass('a');
$b = new MyClass('b');

echo addNumbers($a, $b);
?>
خروجی مثال بالا عدد 13 خواهد بود، همان طور که مشخص است آرگیومنت های تابع از فراخوانی کلاس MyClass با دو پارامتر a و b مقداردهی و در تابع از آبجکت myInt مقادیر دریافت شده اند.
نکته: این شکل استفاده از آرگیومنت های توابع برای برنامه نویسی معمول کاربرد آنچنانی ندارد اما در برنامه نویسی پیشرفته و شی گراء ممکن است کاربردی باشد که جهت آشنایی بیشتر توضیح داده شد.

توابع درونی (Predefined یا Internal (built-in)) در PHP


در اغلب زبان های برنامه نویسی متدها و توابعی به صورت از قبل تعریف شده و آماده وجود دارد که به کمک آنها می توانیم روندهای معمول آن زبان را با سرعت و سهولت بیشتری انجام دهیم، PHP نیز از این قاعده مستثنی نیست و در هسته مفسر آن توابع درونی (Predefined یا Internal (built-in)) به تعداد خیلی زیادی جهت سرعت بخشیدن به روند کار کدنویسی از قبل تعریف شده و توسط برنامه نویسان قابل استفاده است، در لیست زیر سایت مرجع php.net این توابع و متدها را به ترتیب حروف الفبا به همراه توضیحاتی درج کرده است که مرور آنها جهت آشنایی کلی و مراجعات بعدی خالی از لطف نیست:
https://www.php.net/manual/en/indexes.functions.php
برای آشنایی بیشتر در ادامه برخی توابع درونی پرکاربرد زبان PHP را به همراه نمونه کد بررسی می کنیم.
- تابع strlen و mb_strlen
برای به دست آوردن طول رشته (تعداد کاراکتر) از تابع strlen استفاده می کنیم، حالت multi-byte این تابع برای کار با متون یونیکد مانند زبان فارسی (UTF-8) می تواند کاربرد داشته باشد، مثال:
<?php
$str = "text";
echo strlen($str);
?>
خروجی مثال بالا عدد 4 خواهد بود.
<?php
mb_internal_encoding("UTF-8");
$str = "متن";
echo mb_strlen($str);
?>
خروجی مثال بالا عدد 3 خواهد بود.
- تابع str_replace
برای جایگزینی یک مقدار رشته ای با مقادیر دیگر از تابع str_replace استفاده می کنیم، مثال:
<?php
$str = "PHP is so difficult to learn!";
echo str_replace('difficult', 'easy', $str);
?>
خروجی نمونه کد بالا به صورت زیر خواهد بود:
PHP is so easy to learn!
- تابع trim
برای حذف فضای خالی از ابتدا و انتهای رشته از تابع trim استفاده می کنیم، مثال:
<?php
$str = " PHP ";
echo strlen($str);
$str = trim($str);
echo '<br>';
echo strlen($str);
?>
خروجی مثال بالا به صورت زیر خواهد بود:
5
3
- تابع ceil
برای گرد کردن به بالای اعداد اعشاری به نزدیکترین عدد صحیح از تابع ceil استفاده می کنیم، مثال:
<?php
$num = 3.2;
echo ceil($num);
?>
خروجی مثال بالا عدد 4 خواهد بود.
floor و round دو تابع دیگر مشابه با عملکرد متفاوت در این زمینه هستند.
- تابع count
برای شمارش عناصر آرایه یا آبجکت می توانیم از تابع count استفاده کنیم، مثال:
<?php
$array = Array("a", "b");
$count = count($array);
if($count < 2){
    echo "Error!";
} else {
    echo "Ok! count array is: " . $count;
}
?>
خروجی نمونه کد بالا به صورت زیر خواهد بود:
Ok! count array is: 2
تعداد توابع درونی PHP بسیار زیاد است و در اینجا صرفا جهت نمونه و آشنایی بیشتر چند مثال ذکر شد، اما آیا باید همه این توابع را به حافظه بسپاریم؟!
جواب قطعا خیر خواهد بود، هیچ نیازی نیست لیست توابع را حفظ کنیم و چنین کاری عملا هم حداقل به راحتی ممکن نیست، کافی است در هر برنامه ای که می خواهیم بنویسیم توابع مرتبط با فرآیندهای آن برنامه را از طریق جستجو یا مراجعه به نمونه کدها و منابع مرجع پیدا، با کارکردشان آشنا شده و در نهایت در کدهایمان از آنها استفاده کنیم، البته برخی توابع PHP پرکاربرد و متداول هستند که به مرور و به صورت خودکار در ذهنمان حفظ می شوند.
sectionدسته بندی: آموزش مقدماتی » PHP
related مطالب بیشتر:
» آموزش برنامه نویسی وب با PHP
» توابع کار با آرایه در PHP - بخش دوم
» عملگرها (Operators) در PHP
» آرایه (Array) در برنامه نویسی PHP
» تعریف و استفاده از متغیر (Variable) در PHP
commentنظرات (۵۹ یادداشت برای این مطلب ارسال شده است)
more یادداشت های جدید بر اساس تاریخ ارسال در انتهای یادداشت های موجود نمایش داده می شوند.
نویسنده: Matori73
۰۳:۱۵ ۱۳۹۴/۱۲/۰۷
درود، خسته نباشید !
در مورد دریافت اطلاعات لینک از سایت، سوالی داشتم از حضورتون ..
برای دریافت عنوان سایت از لینک، فانکشن زیر رو نوشتم :
function get_title($url){
$str = file_get_contents($url);
if(strlen($str)>0){
$str = trim(preg_replace('/\s+/', ' ', $str));
preg_match("/\<title\>(.*)\<\/title\>/i",$str,$title);
return $title[1];
}
}
و به این شکل هم فراخوانی کردم :
<?= '<a rel="nofollow" target="_blank" href="' . $sk['story']['ulink'] . '" >لینک: ' . get_title($sk['story']['ulink']) . '</a>' ;?>
خروجی درست هست منتها
get_title($sk['story']['ulink'])
در سایت مشکل ایجاد میکنه و کل سایت (لینکی که بهش میدیم !) رو بارگذاری میکنه در تگ a ! امکانش هست که فقط Title اون سایت در خروجی نمایش داده بشه و صرفا فقط متن باشه و کل سایت رو بارگزاری نکنه !؟
تشکر ..
پاسخ: 
متاسفانه به جهت ناقص بودن کد امکان تست میسر نیست، البته این کد با سورس های استاندارد درست عمل می کند، منتها باید آدرس مورد نظر خود را درج کنید تا بتوانیم روی آن آدرس ایرادات را رفع کنیم.
نویسنده: حسین
۲۲:۲۳ ۱۳۹۵/۰۱/۱۰
با سلام خدمت استاد گرامی
یه تابع میخوام که کاربرو بفرسته یه یک صفحه خاص مثلا کد زیر میخوام اگر بدون زدن دکمه وارد صفحه مورد نظر شده بود برگرده به صفحه قبل
{} if(isset($_POST['submit']))
پاسخ: 
می توانید از دستور header در PHP برای تنظیم یک Location HTTP استفاده نمائید، مثال:
header('Location: http://www.example.com/');
اطلاعات بیشتر:
http://php.net/manual/en/function.header.php
نویسنده: ارشاد
۰۱:۰۰ ۱۳۹۶/۰۳/۰۹
سلام خسته نباشید
من میخوام تعدا ورودی تابع رو پویا کنم یعنی کاربر با تابع یه بار 2 تا آرگومان بفرسته یه بار 3 تا یه بار ده تا یعنی ثابت نشه اینطوری که حتما باید 3 تا بفرسته
function calculator($numx,$numy,$numz)
آیا راه حلی هست؟
پاسخ: 
با تابع func_num_args و func_get_arg این کار شدنی است، مثال:
function foo(){
$numArgs = func_num_args();

echo 'Number of arguments:' . $numArgs . "\n";

if ($numArgs >= 2){
echo 'Second argument is: ' . func_get_arg(1) . "\n";
}

$args = func_get_args();
foreach ($args as $index => $arg){
echo 'Argument' . $index . ' is ' . $arg . "\n";

unset($args[$index]);
}
}
foo(1, 2, 3);
نویسنده: مینا
۲۱:۴۵ ۱۳۹۸/۰۷/۱۶
سلام .
ببخشید من سوالی که داشتم مربوط به این پست نیست نمیدونستم کجا بپرسم !
ببینید من در صفحه اول با این دستور
$_SESSION['_ky']=$_SERVER['REMOTE_ADDR'];
ip فرد میگیرم و در صفحه دوم SESSION['_ky'] نمایش میدهم .
در سیستم خودم درسته یعنی هر ip که در صفحه اول ذخیره میکنم همون ip در صفحه دوم نمایش میده .
اما در موبایل با هر رفرش صفحه دوم این ip عوض میشود!
من روی هاست واقعی آپلود کردم و چک میکنم مثلا روی دوتا سیستم امتحان کردم درست بود ولی روی موبایل مشکل داره!
این عملیات با تابع
$_SESSION['_v']=rand(10,100); 
انجام دادم یک عدد رندوم انتخاب میکنم در هر دوتا صفحه مشابه هست و مشکلی نداره در سیستم و موبایل هم امتحان میکنم درسته (این کار بخاطر سیشن ها انجام دادم احتمال دادم مشکل از سیشن باشه که نبود)
فقط مشکلم با ip هست! نمیدونم باید چیکار کنم در موبایل جواب نمیده من این ip برای اعتبار سنجی کاربران زمان لاگین و کنترل پنل میخواستم استفاده کنم
پاسخ: 
احتمالا مشکل زمانی به وجود می آید که اتصال به اینترنت با برنامه های پراکسی انجام شود که در این حالت تغییر IP عملا صورت می گیرد و رفتار مفسر PHP طبیعی است، بهتر است برای دریافت IP اصلی کاربر از تابع زیر استفاده کنید که پراکسی را هم بررسی می کند:
function getRealIP() {
if(!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif(!empty($_SERVER['HTTP_X_FORWARDED'])) {
$ip = $_SERVER['HTTP_X_FORWARDED'];
} elseif(!empty($_SERVER['HTTP_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_FORWARDED_FOR'];
} elseif(!empty($_SERVER['HTTP_FORWARDED'])) {
$ip = $_SERVER['HTTP_FORWARDED'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}

return $ip;
}

$ip = getRealIP();
با توجه به اینکه IP ممکن است با هر قطع و وصل اتصال اینترنت تغییر کنید شاید بهتر باشد صرفا User Agent کاربران را بررسی کنید.
نویسنده: امیرحسین
۰۷:۰۸ ۱۳۹۹/۰۸/۲۷
سلام استاد عزیز وقت بخیر
من یه سوال در مورد function use داشتم اگه ممکنه با مثالی کاربردی توضیح بدید که کارش چیه :
نمونه کد:
function ($x, $y) use ($y)
{
}
پاسخ: 
عبارت use یک statement (دستور) است که چند کاربرد در PHP دارد:
- دسترسی به منبعی خارج از محدوده (Scope) مانند مثالی که درج کرده اید.
در توضیح این کاربرد use فرض کنیم نمونه کدی به شکل زیر در برنامه داریم:
<?php
$x = 5;
$y = 1;
$myFunc = function(){
$x++;
$y++;
$r = $x + $y;
echo $r;
};
$myFunc();
?>
در حالت عادی تابع تعریف شده برای متغیر myFunc به متغیرهای خارج از خود دسترسی ندارد و در صورت اجرای برنامه خطای
Notice: Undefined variable
دریافت می کنیم و نتیجه عدد 2 خواهد بود، اما اگر کدها را به این شکل تغییر دهیم:
<?php
$x = 5;
$y = 1;
$myFunc = function() use ($x, $y){
$x++;
$y++;
$r = $x + $y;
echo $r;
};
$myFunc();
?>
خطا رفع و نتیجه عدد 8 خواهد بود.
- ایجاد نام مستعار (Alias) در کدهای PHP، به فرض برای تشخیص دو تابع هم نام در دو دایرکتوری متفاوت از برنامه.
در توضیح این قابلیت use فرض کنیم سه فایل با نام های a.php، b.php و index.php داریم، در فایل a.php کد زیر:
<?php
class MyClass {
public $num;

public function methodOfA($num){
$this->num = $num + 1;
return $this->num;
}
}
?>
در فایل b.php کد زیر:
<?php
class MyClass {
public $num;

public function methodOfB($num){
$this->num = $num - 1;
return $this->num;
}
}
?>
و در فایل index.php کد زیر را داشته باشیم:
<?php
include('a.php');
include('b.php');

$call = new MyClass();
echo $call->methodOfA(5);
?>
در این حالت اگر فایل index.php را اجرا کنیم به علت هم نام بودن دو کلاس در فایل های a و b خطای زیر را دریافت می کنیم:
Fatal error: Cannot redeclare class MyClass
برای رفع این مشکل از namespace و use به شکل زیر استفاده می کنیم، در فایل a.php:
<?php
namespace FileA;

class MyClass {
public $num;

public function methodOfA($num){
$this->num = $num + 1;
return $this->num;
}
}
?>
در فایل b.php:
<?php
namespace FileB;

class MyClass {
public $num;

public function methodOfB($num){
$this->num = $num - 1;
return $this->num;
}
}
?>
و در نهایت در فایل index.php:
<?php
include('a.php');
include('b.php');

use FileA\MyClass as A;
use FileB\MyClass as B;

$call = new A();
echo $call->methodOfA(5);
?>
با اجرای فایل index.php در خروجی عدد 6 چاپ می شود.
در کل در این شکل معمولا از use در پروژه های گروهی بزرگ که احتمال انتخاب عبارات مشترک برای تعریف کلاس ها و متدها وجود دارد استفاده می کنند.
نویسنده: محمد رستمی
۰۱:۱۹ ۱۳۹۹/۰۹/۰۵
سلام اگه میشه لیست توابع و کاربردشونو توی یه فایل pdf بزارین
پاسخ: 
با توجه به تعداد بالای توابع PHP می توانید از لیست آماده زیر استفاده کنید:
https://www.php.net/manual/en/indexes.functions.php
نویسنده: امیرحسین
۱۰:۳۹ ۱۳۹۹/۰۹/۱۶
سلام وقت بخیر بابت پاسخ گویی قبلیتون مچکرم،
من یکی از کاربران قدیمی سایت وبگو هستم همیشه سلامت باشید، سوالی داشتم در واقع مشکل من اینه که من یک جدول در دیتابیس دارم که
جدول کاربرانو دارم (ایدی-نام-نام خانوادگی-...)
جدول دوم (ایدی-مبلغ معامله- ایدی کاربر اول-ایدی کاربر دوم)
که جدول دوم دو تا ستون داره که کلید خارجی جدول کاربرانه که اطلاعاتش به این صورته
40|50000|100|200
یعنی کاربری که ایدیش 100 هست با کاربری که ایدیش 200 هست مبلغ 50 هزار تومن معامله کرده اند و کد این معامله 40 هست خب استاد سوالم اینه که من اینجا دوتا کلید خارجی دارم که ابشاری هست یعنی هر کدوم از کاربرا پاک شن این معامله از بین میره، ولی من نمیخوام این اتفاق بیوفته، اگر جفت کاربرا پاک شدن اونوقت معامله میتونه پاک بشه ولی وقتی یکی از کاربرا پاک شدن معامله نباید پاک بشه چیکار میتونم کنم؟ از طریق کد php میتونم کنترلش کنم ولی میخواستم بدونم mysql تا این حد قدرت داره کار منو راحت کنه؟
پاسخ: 
در MySQL خیلی نمی توانیم بر روی این موارد مانور دهیم، تا آنجا که از توضیحات متوجه شدیم می شود قبل از حذف کاربر با دستور ALTER ستون مورد نظر را از حالت FOREIGN KEY خارج کنیم تا با حذف ستون کلید خارجی معامله مرتبط حذف نشود (هرچند به نظر اگر کلید خارجی در جدول دیگر استفاده شده باشد و دارای محتوا باشد نباید بتوانیم کلید را حذف کنیم؟!)، به فرض:
ALTER TABLE table_name DROP FOREIGN KEY col_constraint_name;
برای بدست آوردن مقادیر CONSTRAINT متناظر هر ستون دستور زیر را اجرا و از قسمت Print view (with full texts) در برنامه phpMyAdmin نتیجه استخراج می شود:
SHOW CREATE TABLE table_name;
البته اگر با PHP بهینه و بدون افت معنادار سرعت پردازش برنامه بتوانیم این کار را مدیریت کنیم بهتر است و کنترل بیشتری روی فرایندها خواهیم داشت، در صورت تمایل لطفا یک نمونه ساختار SQL به همراه محتوا از دیتابیس مد نظر به آدرس ایمیل ما (موجود در بخش تماس) ارسال کنید تا امکان تست و بررسی بیشتر وجود داشته باشد.
نویسنده: امیرحسین
۰۶:۴۲ ۱۳۹۹/۰۹/۲۴
سلام وقت بخیر، بابت پاسخ قبلی ممنونم
فرض کنید من یک سایتی دارم که توش شرط بندی انجام میدن کاربران مثلا یک نفر یک شرطی گذاشته و تعداد زیادی کاربران اون شرطو میبینند حالا هر کاربری زودتر اون شرطو بگیره شرط ماله اون میشه حالا سه تا کاربر همزمان میان اون شرطو بگیرن اینکار انجام میشه ولی من نمیخوام شرط ماله سه نفر باشه بلکه هرکی زودتر بگیره شرط ماله اونه در واقع اگر با فاصله های زمانی 1 ثانیه اقدام به گرفتن شرط کنند مشکلی نداره ولی اگر همزمان بگیرند مشکل داره من اینجا اول یه دستور سلکت نوشتم و چک کردم که آیا این شرطو کسی گرفته یا خیر، بعد شرطو ثبت کن و ماله اونی که میگیره بشه، حالا مثلا سه نفر همزمان میان اقدام به گرفتن شرط میکنند، همزمان اون سلکتو انجام میشه واسه هر سه کاربر و به تک تک اونا میگه که شرطو کسی نگرفته و چون همزمانه هر سه تا میتونن بگیرند اینجا دستور سلکتی که بررسی میکنه ایا کسی شرطو گرفته یا خیر عملا کار نمیکنه چون همزمان هستن خب من اینجا یه حرکتی زدم گفتم هرکسی شرطو گرفته باشه رو پاک کن یعنی کاری کردم کسی شرطو اگه گرفته باشه هم پاک میکنه بعد گفتم شرطو بگیر یعنی قبلا select انجام میدادم و بعدش insert ولی حالا اول delete انجام میدم بعدش insert اینجوری مشکلم حل میشه مثلا اگه سه نفر همزمان شرطو بگیرن اول دیلیت اتفاق میوفته و بعد اضافه میشه، اینجوری نفر اخر شرطو میگیره اگر همزمان باشه
خب استاد بجای اینکه من این راهو برم شما راه حل دیگه ای پیشنهاد ندارید؟ مثلا میدونم درخواست هارو صف بندی کنم اما نمیدونم چطوری
و سوال دومم اینه که LOCK TABLE ها به چه دردی میخورند آیا مشکل سوال اول منو میتونه حل کنه ؟
با تشکر فراوان
پاسخ: 
در حالت کلی خود MySQL با توجه به موتور استفاده شده یکی از حالت های Table-Level Locking (برای موتور MyISAM) و Row-Level Locking (برای موتور InnoDB) را اعمال می کند و عملا تداخل دو نشست همزمان در یک جدول یا ردیف ممکن نیست، انتخاب یکی از موتورهای بالا بستگی به هدف و نیازهای برنامه دارد که خود بحث مجزایی می طلبد، در موتور MyISAM کل جدول (برای چند هزارم ثانیه) قفل می شود و در موتور InnoDB این کار برای ردیف درگیر پردازش اتفاق می افتد، در کنار این قابلیت قسمت کدنویسی سمت سرور نیز باید دقیق نوشته شود، به نظر در شیوه شما اشکالی وجود دارد و هر کاربری در هر زمانی می تواند شرط گرفته شده قبلی را ثبت کند، به فرض کاربر 3 شرط را در 12:33:21 ثبت می کند و کاربر 4 با توجه به اجرای ابتدایی پرس و جوی DELETE می تواند شرط را هر زمان دیگری (به فرض 13:16:20) ثبت کند!، در تئوری می توانیم برای هر شرط یک ستون status داشته باشیم که در صورت ثبت توسط هر کاربری به فرض مقدار آن UPDATE و 1 شود، در هر تقاضای ثبتی ابتدا ستون وضعیت شرط مربوطه SELECT و چک می شود و اگر 0 بود کاربر مجاز به ثبت و UPDATE وضعیت به 1 است، به این صورت با توجه به عدم امکان اجرای نشست همزمان در MySQL عملا تداخلی بروز نمی کند.
اگر علاوه بر این می خواهید اطمینان بیشتری داشته باشید می توانیم برای هر شرط یک ستون user داشته باشیم، هر کاربری که ابتدا شرط را گرفت user او در ستون مربوطه ثبت و status را UPDATE کند، در پرس و جوی UPDATE در قسمت WHERE ستون status را دخیل کنیم، به فرض
UPDATE tbl SET user = 'user', status = '1' WHERE id = 1 AND status = 0
برای بررسی UPDATE شدن موفقیت آمیز ستون مورد نظر هم می توانیم از mysqli_affected_rows استفاده کنیم:
https://www.php.net/manual/en/mysqli.affected-rows.php
یک راه حل دیگر ایجاد جدول شرط های گرفته شده با یک ستون یکتا است که می تواند شامل شماره ID شرط مورد نظر باشد، این ستون را می توانیم به صورت UNIQUE INDEX در نظر بگیریم و در هر ثبت شرطی اگر قبلا ID در این جدول ثبت شده باشد اجازه ثبت مجدد داده نمی شود، برای تبدیل ستون به حالت UNIQUE INDEX می توانیم از نمونه پرس و جوی زیر استفاده کنیم:
CREATE UNIQUE INDEX unique_index_name  ON `tbl_name` (`col_name`);
نویسنده: امیرحسین
۲۱:۳۵ ۱۳۹۹/۰۹/۲۴
سلام استاد عزیز من کاری که کردم رو کامل بزارم توضیح بدم در مورد سوال قبلیم:
من یک ربات تلگرام شرط بندی درست کردم که یک جدول دارم به اسم:
games ستون هاش:
gameId | gameName
و یک جدول دیگه دارم به اسم
gameSelect ستون هاش:
id | gameId | user_id | price
به فرض در جدول game لیست بازی هایی دارم :
1 | استقلال
2 | پرسپولیس
3 | منچستر
و داده های جدول دوم:
1 | 1 | 1 | 50000
یعنی کاربری که ایدیش 1 هست 50000 هزار تومن رو بازی که ایدیش 1 هست شرط بسته فرض کنیم لیست بازی ها در گروهی هست کاربران رو هر کدوم از این پیام ها ریپلای کنن و بگن قبول این بازی رو برمیدارن حالا اگه دو کاربر همزمان یک بازیو ریپلای کنه و قبول بفرسته اینجا هر دو کاربر ثبت میشه، من میخوام کاری کنم که هر کاربر فقط مجاز به گرفتن یک بازی باشه یعنی هر کاربر مجاز هست فقط یک بازی رو انتخاب کنه یا به عبارتی یک بازی نمیتواند توسط دو کاربر در جدول selectGame ثبت بشه
حالا کاری که من کردم اینه:
select * from gameSelect where `user_id` = '1' and `game_id` = '2' 
if($row->num_rows){
insert into selectGame(`gameId`,`user_id`,`price`) values('2', '1','5000')
}
اینجا اول چک کردم کاربری بازی رو انتخاب کرده یا خیر اگه نتیجه دستور select چیزی برگردونده نشه یعنی کاربری این بازیو انتخاب نکرده و اجازه به ثبت میده حالا دو نفر همزمان میان بازیو انتخاب میکنن دستور سلکت به هر دو نفر میگه بازی وجود نداره و اجازه ثبت به جفتشون میده ولی اگه این دو نفر با فاصله های زمانی 1 ثانیه ای نوبتی بازی رو بگیرند دیگه اجازه ثبت نمیده و پیغام میده که این بازی رو قبلا کاربری انتخاب کرده ولی به صورت همزمان این اتفاق نمیوفته
پاسخ: 
آن طور که متوجه شدیم بررسی های شما ایراد دارند (تئوری برنامه را خوب تحلیل می کنید اما در پیاده سازی درست کدها مشکل دارید)، اگر بخواهید ثبت نشدن بازی توسط کاربران دیگر را بررسی کنید پرس و جو باید شبیه حالت زیر باشد:
SELECT id FROM gameSelect WHERE `game_id` = '2' LIMIT 1
if($row->num_rows > 0){
//این بازی قبلا توسط کاربر دیگری ثبت شده است
} else {
//پرس و جوی ثبت جدید
}
در مورد همزمانی ثبت هم در پاسخ قبلی توضیح دادیم که عملا ثبت همزمان اطلاعات در MySQL بر روی یک جدول یا ردیف (با توجه به موتور استفاده شده) ممکن نیست پس از این بابت جای نگرانی نیست.
نویسنده: امیرحسین
۰۴:۱۳ ۱۳۹۹/۰۹/۲۵
SELECT id FROM gameSelect WHERE `game_id` = '2' LIMIT 1
if($row->num_rows > 0){
//این بازی قبلا توسط کاربر دیگری ثبت شده است
} else {
//پرس و جوی ثبت جدید
}
سلام استاد من اینجا اصلا نیازی به limit ندارم چون میخوام چک کنم رکوردی از بازی که ایدیش 2 هست در gameSelect ثبت شده یا خیر خب اگه تعداد بیشتر از 1 باشه یعنی نباید اجازه بده و بگه کاربری دیگر اینکارو کرده است، پس برای من 0 بودن مهمه که اگه تعداد 0 بود اجازه ثبت بده پس اینجا limit ضروری نیست درسته ؟
در مورد این
if($row->num_rows > 0)
با
if($row->num_rows)
میتونم بگم هیچ فرقی ندارن و هر دو یک منظورو میرسونن از اونجایی که من 0 بودن برایم مهم هست شرط چک میکند مقدار num_rows ترو هست خب مسلما از 1 یا هرچی بیشتر مقدار ترو هست پس میگه کاربر از قبل وجود دارد پس این قسمت هم مشکلی نداره شما همان کدهای منو به خودم تحویل دادید
ببینید استاد من اینو بررسی کردم بارها و میدونم که mysql این باگ رو داره من با رفیقم هماهنگ کردم گفتم ثانیه ساعت اگر به 59 رسید بیا تو گروه و اون بازی رو بگیر، بعد خودمم به محض رسیدن ثانیه به 59 همینکارو میکنم (که همزمان بودن را برقرار کنم) خب اینجا چه اتفاقی میوفته؟
فرض کنید همزمان صفحه اجرا شده و در آن واحد فیلد چک میشه به رفیقم میگه بله کسی نیست و اجازه ثبت شدن رو بهش میده، به من هم چون همان لحظه با رفیقم صفحه رو اجرا کردم به منم میگه وجود نداره پس چون همزمان بود به جفتمون گفت وجود نداره و واقعا هم وجود نداره! بخاطر همین جفتمون اجازه ثبت میده !!!!
متوجه منظورم میشوید؟ من اینجا چیکار میتونم انجام بدم به نظر شما، ایا درخواست هارو تو صف بزارم که درخواست های همزمان رو با زمان های متفاوت به سرور بفرسته (با ردیس)
ولی من بجای اینکه از این کد ها استفاده کنم:
SELECT id FROM gameSelect WHERE `game_id` = '2' LIMIT 1
if($row->num_rows > 0){
//این بازی قبلا توسط کاربر دیگری ثبت شده است
} else {
insert into selectGame(`gameId`,`user_id`,`price`) values('2', '1','5000')
}
اومدم از این کدهای زیر استفاده کردم که مشکلم به طور کامل حل شده است:
SELECT id FROM gameSelect WHERE `game_id` = '2' LIMIT 1
if($row->num_rows > 0){
//این بازی قبلا توسط کاربر دیگری ثبت شده است
} else {
delete FROM gameSelect WHERE `game_id` = '2' [LIMIT 1]
insert into selectGame(`gameId`,`user_id`,`price`) values('2', '1','5000')
}
اینجوری مشکلم به طور کامل حل شده است، حالا فرض کنیم همزمان منو دوستم داریم صفحه رو اجرا میکنیم، چه اتفاقی میوفته بیاین تحلیل کنیم:
اینجا رفیقم صفحه رو اجرا میکنه چک میکنه میبینه ایا کسی این شرطو گرفته یا خیر اگر کسی نگرفته باشه برنامه هرچی کاربر از قبل اونو انتخاب کرده باشه رو پاک میکنه (جهت اطمینان) بعد مجدد ثبت میکنه واسه من که همان لحظه در ان واحد صفحه رو دارم اجرا میکنم چون دستور سلکت نمیتونه اینو پوشش بده منم یه دیلیت و سپس اینزرت اجرا میکنم پس اینجوری شد که رفیقم یک دیلیت و یک اینزرت اجرا میکنه و من هم یک دیلیت و یک اینزرت ، بنابراین فقط یک نفر باقی میمونه که اون بازیو دریافت کرده باشه :)) نظر شما چیه از این راه ؟ ایا راه بهتری سراغ دارید ، ایا با روش قفل کردن جداول ممکنه باعث شه از این راه استفاده نکنم؟
پاسخ: 
آنطور که ما از توضیحات متوجه شدیم یک جدول وجود دارد که فقط یک کاربر (اولین نفر) می تواند یک بازی را در آن ثبت کند (از هر بازی صرفا 1 رکورد مجاز به ثبت است)، خب حالا دستور شما را که در یادداشت قبل ارسال کردید مرور کنیم:
select * from gameSelect where `user_id` = '1' and `game_id` = '2'
معنی این پرس و جو:
از جدول gameSelect ردیف ها را انتخاب کن جایی که user_id برابر 1 باشد و game_id برابر 2
خب همین پرس و جو اشکال دارد و فقط ثبت شدن بازی 2 را برای کاربر 1 بررسی می کند و به سایر کاربران کاری ندارد! در صورتی که هدف بررسی ثبت نشدن بازی توسط تمام کاربران است و نباید محدود به user_id با مقدار 1 باشد، پس پرس و جو حداقل باید به شکل زیر اصلاح شود:
SELECT id FROM gameSelect WHERE `game_id` = '2'
اما چرا از LIMIT استفاده کنیم؟ اجباری وجود ندارد و صرفا جهت بهینه شدن پرس و جو و Performance کار استفاده می کنیم، چطور؟ فرض کنید 1 میلیون رکورد در دیتابیس وجود دارد و طبق پرس و جوی ما MySQL ردیف به ردیف اطلاعات ستون game_id را بررسی می کند تا به یک رکورد مناسب قسمت WHERE برسد، با پیدا کردن اولین رکورد جستجو متوقف نمی شود چون محدود نشده و تا ردیف 1 میلیون ادامه پیدا می کند! با در نظر گرفتن LIMIT هر کجا اولین ردیف پیدا شد جستجو ردیف های بعدی نیازی نیست و فرآیند خاتمه پیدا می کند.
در مورد
if($row->num_rows > 0)
با
if($row->num_rows)
ببینید شما می خواهید ثبت نشدن بازی توسط هیچ کاربری را بررسی کنید و قاعدتا باید پرس و جوی ثبت بازی توسط هر کاربری را اجرا و دنبال نتیجه 0 از پرس و جو باشید که اگر نتیجه 0 بود رکورد جدید را INSERT کنید، این پرس و جو:
select * from gameSelect where `user_id` = '1' and `game_id` = '2' 
if($row->num_rows){
insert into selectGame(`gameId`,`user_id`,`price`) values('2', '1','5000')
}
یعنی اگر کاربر 1 بازی 2 را ثبت کرده بود قسمت INSERT را اجرا کن!! در صورتی که باید چک کنیم اگر هیچ کاربری بازی 2 را ثبت نکرده بود INSERT را برای کاربر فعلی اجرا و بازی 2 را برای او ثبت کن؟!
در مورد ثانیه 59 و... ببینید اگر ساختار کدها درست تعریف شده باشد عملا امکان ندارد حتی در یک ثانیه دو درخواست همزمان توسط MySQL پردازش شود (با توجه به بحث Locking) و چنین چیزی ممکن نیست، اینکه شما ایرادی در برنامه مشاهده می کنید از کدنویسی سمت سرور و پیاده سازی ساختار است که باید با توجه به توضیحات هنگام ثبت فرم بررسی ها را انجام دهید که هر کاربری زودتر رکورد را ثبت کرد بازی برای او باشد، مگر اینکه ما کلا ساختار و هدف برنامه را اشتباه برداشت کرده باشیم؟!
نویسنده: امیرحسین
۱۴:۲۰ ۱۳۹۹/۰۹/۲۶
ممنون از توضیحات شما قسمت LIMIT واقعا کاربردی بود توضیحاتتون لازمم میشه واقعا دست شما درد نکنه اون قسمت هارو من یه پروژه میزنم بهتون ایمیل میکنم کدها رو ببینید خودتون تا منظورم واضح باشه
یه سوال دیگه داشتم کدوم کووری های زیر سریعتر اجرا میشوند ؟
SELECT COUNT(*) `ok` FROM `users` WHERE `nickName` = 'Amir'
$res->fetch_assoc()['ok']

SELECT `id` FROM `users` WHERE `nickName` = 'Amir' LIMIT 1
$res->num_rows
فرض کنید میخوام بررسی کنم نام مستعار وجود دارد یا خیر
پاسخ: 
هر کدام از روش های بالا می توانند کاربرد خودشان را داشته باشند و البته با نتیجه یکسانی استفاده شوند، استفاده از COUNT زمانی که هدف شمارش تعداد ردیف های از پیش نامشخصی است می تواند بهینه باشد، اما LIMIT و num_rows برای پرس و جوهای محدود به تعداد خاص و از پیش مشخص (به فرض در اینجا ما صرفا 1 ستون را نیاز داریم) یا زمانی که هدف صرفا شمارش نیست و استخراج اطلاعات را هم شامل می شود می تواند بهینه باشد، اگر هر دو پرس و جو نامحدود باشند در کل سرعت COUNT بیشتر است اما اگر هدف 1 ستون باشد پرس و جوی با LIMIT بهتر است، نکته خیلی مهم و کمک کننده به مقوله سرعت ایجاد INDEX بر روی ستون هایی است که در قسمت WHERE درگیر می شوند، با ایندکس گذاری MySQL نتایج را به ترتیب حروف، اعداد و... مرتب سازی کرده و موقع جستجو به سرعت ردیف مورد نظر را شناسایی می کند و به اینصورت در حداقل زمان ممکن کار با حجم زیادی از اطلاعات امکانپذیز است (با برنامه phpMyAdmin یا با دستور ALTER می توانیم قابلیت Index را به ستون های مورد نظر اضافه کنیم).
ALTER TABLE `users` ADD INDEX `nickName_index` (`nickName`)
نویسنده: امیرحسین
۱۸:۰۸ ۱۳۹۹/۱۰/۲۵
سلام استاد وقت بخیر
ممنون از پاسخ گویی های قبلی یه سوال دیگه داشتم:
SELECT `games`.* FROM `deals`,`games` WHERE (`user_id_one` = '237' OR `user_id_two` = '237') AND `games`.`gameWin` = '' AND `deals`.`gameId` = `games`.`id`
این کووری رو من ترتیب شرط هاشو چطوری باید بزارم تا سریعتر اجرا بشه ؟ الان این ترتیبی که استفاده کردم درسته ؟ تو قسمت where که پیوند دو تا جدول هست گفتم از جدول معامله اون کاربری که یوزر ایدیش 237 هست رو انتخاب کن اول، دوتا ستونشاین جدول معاملات هست که دو تا کاربر داخلشون هست بعد شرط بعدی هم اینه که بازی نتیجش معلوم نشده باشه، و شرط بعدی هم شرط پیوند هست، خب این پیوندو من اول استفاده کنم سرعت میره بالا یا اخر، فکر میکنم اخر استفاده کنم سرعت بیشتری دارم ولی همین شرطو من میتونم خلاصه ترشم کنم:
SELECT `games`.* FROM `deals`,`games` WHERE '237' IN(`user_id_one`,`user_id_two`) AND `games`.`gameWin` = '' AND `deals`.`gameId` = `games`.`id`
این هم هیچ مشکلی نداره و کار میکنه، ایا اینجوری که من خلاصه کردم و از IN استفاده کردم سرعتو بیشتر میکنه ؟ سوال من فقط بهینه نوشتن کووری هست
پاسخ: 
در کل برای دو نمونه بالا تفاوت محسوسی به لحاظ سرعت پردازش پرس و جو وجود ندارد اما حالت دوم خالاصه تر و در شرایط مساوی ترجیح دارد، برای افزایش سرعت بیشتر روی ایندکس گذاری ستون ها کار کنید.
نویسنده: امیرحسین
۰۸:۲۹ ۱۳۹۹/۱۰/۲۶
ُسلام وقت بخیر
select * from `users`,`posts` WHERE `users`.`id` = `posts`.`user_id` AND `users`.`id` = '17'
این کووری بالا اول پیوند میخورد بعد قسمت کاربر با ایدی 17 گرفته میشود فرض کنید ما هزار تا کاربر داریم این هزار تا کاربر با جدول پست اول پیوند داده میشن سپس بین کاربرا اونی که ایدیش 17 هست رو میگیره این اشتباهه به کووری پایین دقت کنید
select * from `users`,`posts` WHERE `users`.`id` = '17' AND `users`.`id` = `posts`.`user_id`
اینجا اول بین هزار اون یدونه کاربری که ایدیش 17 هست گرفته میشه ، سپس همون یدونه با جدول پست ها پیوند میخوره ، خب پسن نتیجه میگیریم کووری دومی خیلی سریعتر خواهد بود شما فکر میکنید تاثیری نداره ؟ اولویت شرط ها خیلی مهمه رعایت کنی ولی همین کووری رو اگه با حالت inner join بنویسیم
select * from `users` INNER JOIN `posts` ON `users`.`id` = `posts`.`user_id` WHERE `users`.`id` = '17'
این کووری هم چون اول قسمت WHERE انجام میشه بعد قسمت ON پس این کووری هم با حالت کووری قبلی برابره
پاسخ: 
به طور کلی چینش دستورات تاثیری در سرعت پرس و جو ندارد چون در نهایت موتور MySQL قبل از اجرا آنها را بهینه (Optimize) می کند (البته در کل پرس و جوها باید منطقی نوشته شوند و تا حد امکان ستون های غیرضرور درگیر نشوند)، همچنین پرس و جوهای درج شده در یادداشت قبل متفاوت از مقایسه شما در این یادداشت است! (دستور IN برای خلاصه کردن OR ها در MySQL استفاده می شود و این خلاصه سازی تاثیر خاصی در سرعت پردازش ندارد)، افزایش سرعت محسوس با ایندکس گذاری (Indexing) ستون های درگیر در قسمت WHERE و ON و IN حاصل می شود.
نویسنده: امیرحسین
۱۶:۲۹ ۱۳۹۹/۱۰/۲۶
بله استاد خیلی ممنون، نمیدونستم خودش Optimize رو انجام میده
در کل من بعد از ایندکس گذاری ها همیشه سعی کردم جوری که با عقل خودم منطقیه ترتیب شرط هارو رعایت کنم برای افزایش سرعت
پاسخ: 
بسیار عالی.
https://dev.mysql.com/doc/internals/en/optimizer.html
more لطفا پیش از ارسال یادداشت نکات زیر را مد نظر داشته باشید:
- موارد غیرمرتبط با مباحث آموزش ها را در فرم منوی "تماس با ما" مطرح و پاسخ را از طریق ایمیل دریافت کنید.
- به سوالات کلی، مبهم و مشکلاتی که تلاشی برای رفع آن نکرده باشید پاسخ مختصر داده خواهد شد.
- کدها و اسکریپت های طولانی را ترجیحا در یک صفحه وب آنلاین قرار دهید تا امکان تست و بررسی وجود داشته باشد.
- از درج عناوین تبلیغاتی در فیلدها خودداری کنید، در صورتی که یادداشت تبلیغاتی تشخیص داده شود حذف خواهد شد.
- تمام یادداشت ها بررسی و زمانی جهت پاسخگویی در نظر گرفته می شود، لطفا از طرح سوالات متعدد خودداری کنید.





5 × 2
 refresh

آخرین دیدگاه ها
more برای دسترسی سریع به یادداشت مربوطه می توانید از لینک مطلب در کادر زیر استفاده کنید.
form کوثر رحیمی
در:
سلام ا ز راهنماییتون ممنونم من تازه وبلاگم رو درست کردم ۱۲ سالمه هر کاری می کنم فیلم در اون قرار نمیگیره همش این خطا...
۱۳۹۹/۱۰/۲۹

form متین
در:
سلام و خسته نباشید من بخوام داده ای که از قبل موجوده رو با متد پست به یک فایل ارسال کنم چجور میشه؟ یعنی...
۱۳۹۹/۱۰/۲۷

form روشنا
در:
سلام ما یه وبلاگ گروهی داریم مختص املاک فایل های جدید و حتی قالب جدید اصلا اعمال نمیشه . حتی راهنمایی که کرده...
۱۳۹۹/۱۰/۲۷

form علی
در:
من در یک سایت سازی سایت ساختم یه بخش داره به نام اسکریپت دلخواه می خوام یه اسکریپتی بذارم که مثلا یه موسیقی وقتی کاربر...
۱۳۹۹/۱۰/۲۷

form امیرحسین
در:
بله استاد خیلی ممنون، نمیدونستم خودش Optimize رو انجام میده در کل من بعد از ایندکس گذاری ها همیشه سعی کردم جوری که با...
۱۳۹۹/۱۰/۲۶

form امیرحسین
در:
ُسلام وقت بخیر این کووری هم چون اول قسمت WHERE انجام میشه بعد قسمت ON پس این کووری هم با حالت کووری قبلی برابره
۱۳۹۹/۱۰/۲۶

form امیرحسین
در:
سلام استاد وقت بخیر ممنون از پاسخ گویی های قبلی یه سوال دیگه داشتم: این هم هیچ مشکلی نداره و کار میکنه، ایا...
۱۳۹۹/۱۰/۲۵

form محمد بیدل بازه
در:
سلام خسته نباشید ببخشید من توی یک قسمت سایتم تصویری دارم و میخوام سمت راست اون تصویر متن بنویسم ولی نمیشه تا متن رو...
۱۳۹۹/۱۰/۲۵

form سلام
در:
و اینکه یه تگ خوب برای فونت معرفی کنید و یه تگ دیگه که متن رو (تیتر مطلب (تست)) در ادامش بنویسه نه اینکه...
۱۳۹۹/۱۰/۲۴

form سلام
در:
سلام وبسایتم را نگاه کنید از چه تگی استفاده کنم تا فاصله بین تیتر مطلب جدید را کاهش دهم؟ (از خطی به خط...
۱۳۹۹/۱۰/۲۴

form وطن
در:
سلام. خسته نباشید. خیلی گشتم درباره یک خطا یا ایراد فنی که چند روز هست در سایت نوشته شده با پی اچ پی (اسکریپت اولوشن)...
۱۳۹۹/۱۰/۲۴

form حورارمی
در:
سلام. من هنوز نمیدونم تو تنظیمات باید کجا رو بگردم تا قالب وبلاگم رو با عکس مورد علاقه ام تغییر بدم. یا نمیتونم...
۱۳۹۹/۱۰/۲۳

form راشد
در:
این روش خیلی طولانیه در فروشگاه من یک برنامه گرفتم که یه عکس توش اپلود کن بهت یک لینک میده در ظرف چند ثانیه و...
۱۳۹۹/۱۰/۲۱

form باسلام
در:
باسلام خدمت شما عزیز زحمت کش، من مطلب را تا آخر مطالعه کردم. من وبلاگم بازدیدای زیادی داره چون تمام مطالبش رو خودم مینویسم و...
۱۳۹۹/۱۰/۲۱

form محمود
در:
سلام و عرض ادب من در سایتم یک قسمت تب ایجاد کردم، متن ها را که در تب می نویسم پاراگراف بندی نمی شوند....
۱۳۹۹/۱۰/۲۱
form علی آقابیگی
در:
سلام خسته نباشید ببخشید من می خواستم کد جدید در وبلاگم بزارم بعد اشتباهی رفتم در قسمت ویرایش کدها و بعد بیشتر کدها را پاک...
۱۳۹۹/۱۰/۲۰
form محمد
در:
سلام. من میخوام با جاوا اسکریپت یک کدی بنویسم که وقتی کاربر روی یک دکمه ‏ای کلیک کرد، یک کد تصادفی برای شمارش ارسال...
۱۳۹۹/۱۰/۲۰
form پوریا
در:
سلام خسته نباشید، ممنونم بابت توضیحات خوبتون، یه مشکلی داشتم میخواستم ببینم امکانش هست راهنمایی کنید؟ فرض کنید یه اینطور متنی داریم: ...
۱۳۹۹/۱۰/۱۹
form seyedsobhanmansouri
در:
سلام خسته نباشید من سایتمو طراحی کردم اما به این مشکلات بر میخورم اول اینکه هدر سایتم نمایش داده نمیشه اصلا و بعد...
۱۳۹۹/۱۰/۱۹
form رضا
در:
سلام. ممنون بابت مطالب مفیدتون. این نوع جستجو به سئو سایت لطمه نمیزنه؟؟؟ چون در این مدل جستجو، مقدار impression میره بالا ولی...
۱۳۹۹/۱۰/۱۹
form mahdi
در:
سلام استاد عزیز ، پس بنظرتون بجای وقت گذاشتن برای یادگیری لاراول و وردپرس ، وقت بزارم که عمیق تر php و ساختار mvc...
۱۳۹۹/۱۰/۱۹
form علی
در:
سلام و ممنون بابت وبسایت عالیتون داخل بعضی سایت ها دیدید مثلا یه متنی شروع به تایپ شدن می کنه و وقتی کامل شد...
۱۳۹۹/۱۰/۱۸
form محمد
در:
سلام خدمت شما دوست عزیز سوالم این بود میخاستم چندتا مثال از این تابع و چند تابع دیگه از خودتون رو برام مثال بزنید...
۱۳۹۹/۱۰/۱۸
form محمود رنجبر
در:
سلام برادر مشکل من تو همین سایتی هست که فرستادم وقتی گزینه خانه رو کلیک میکنم و بعد دکمه بک گوشی رو میزنم بالای صفحه...
۱۳۹۹/۱۰/۱۷
form mahdi
در:
سلام استاد عزیز ، بعد از آموزس php با لاراول کار کنیم بهتره ؟
۱۳۹۹/۱۰/۱۶
form رضا
در:
آدرس رو براتون گذاشتم دامنه قبلا روی یه وبلاگ میهن بلاگ بود چند ماه میشه که از میهن بلاگ خداحافظی کردم ولی هنوز که هنوزه...
۱۳۹۹/۱۰/۱۴
form نیلو
در:
سلام... ببخشید بعد طراحی قالب قالب شیشه ایم هست یا نه؟؟؟
۱۳۹۹/۱۰/۱۳
form مجتهدزاده
در:
سلام من یه فرمی طراحی کردم که توش قراره تعداد زیاد (حدود 10 الی 50) فیلد رو تو دیتابیس اینسرت کنم. آیا باید...
۱۳۹۹/۱۰/۰۸
form مجتهدزاده
در:
سلام لطفا راهنمایی بفرمایید که چه زمانی قبل از متغیر @ استفاده می شه و کاربردش چیه؟ با تشکر
۱۳۹۹/۱۰/۰۶
form ali
در:
سلام چجوری میشه با php بازی هوب رو طراحی کرد
۱۳۹۹/۱۰/۰۶
form رضا
در:
سلام ممنون از سایت خوبتون ایکون سایتم رو توی دسکتاپ درست نشون میده ولی تو گوشی مشکل داره طبق اموزش شما هم انجام دادم...
۱۳۹۹/۱۰/۰۶
form فرانک دستان
در:
سلام من خیلی دوست دارم روی وبلاگم کد اهنگ بزارم ولی هیچ کدوم نمی یاد بهم گفتن از این کدها دیگه پشتیبانی نمی شه شما...
۱۳۹۹/۱۰/۰۵
form مصطفی
در:
سلام. عملگر @ چه زمانی قبل از یک متغییر میاد؟
۱۳۹۹/۱۰/۰۵
form سما
در:
سلام من وقتی میزنم روی مشاهده وبلاگ صفحه فیلتر برام میاد و نمیتونم وبلاگمو ببینم
۱۳۹۹/۱۰/۰۵
form مجتبی
در:
سلام من وبلاگ بلاگفا دارم کدها و جاوا استیکرها رو میزارم تو قسمتشون ولی همه ی کدها رو یکطرف وبلاگ نشون میده چطوری سمت...
۱۳۹۹/۱۰/۰۵
form matin asadi
در:
سلام ممنون بابت سایت خوبتو من یه مشکلی دارم می خواستم کدی برای این مثال زیر بنویسم ولی بلد نیستم ممنون میشم کمک کنید. ...
۱۳۹۹/۱۰/۰۲
form sahar1999
در:
سلام وقت بخیر چطور میتونم در برنامه نویسی سی شارپ هنگام ایجاد پایگاه داده ی MySql نام پایگاه داده رو از txetbox دریافت کنم؟
۱۳۹۹/۱۰/۰۱
  در انتظار بررسی: ۰
 پاسخگویی به سوالات ممکن است تا 24 ساعت زمان ببرد.