الجمعة، 22 سبتمبر 2017

كلاس التحميل الزائد الاصدار الجديد 3.8 php real overloading

بعد غياب طويل اعود لأكتب مقالة جديدة حول التحميل الزائد Overload.

في الاصدار الجديد لكلاس Overloadable الذي نشرت اصدارات سابقة في هذه المدونة قمت باضافات عدد من المميزات وهي:




- عدم الحاجة لوراثة الكلاس overloadable.

- عدم الحاجة لاستخدام الدالة eval.

- تقليل حجم الكلاس overloadable.

- تحتاج لاضافة دالة واحدة في كلاسك لتقوم بكل العمل.

والأن إلى الشرح:

1) قم بتضمين كلاس Overloadable في مشروعك، وهنا سأضيف الكلاس كاملاً لكي تتمكن من رؤية المثال كاملاً..




<?php

/*******************************
 * author  : hishamdalal@gmail.com 
 * version : 3.8
 * create on : 2017-09-17
 *****************************/


class Overloadable
{
 static function call($obj, $method, $params=null) {
  $class = get_class($obj);
  // Get real method name
  $suffix_method_name = $method.self::getMethodSuffix($method, $params);
  
  if (method_exists($obj, $suffix_method_name)) {
   // Call method
   return call_user_func_array(array($obj, $suffix_method_name), $params);
  }else{
   throw new Exception('Tried to call unknown method '.$class.'::'.$suffix_method_name);
  }
 }
 
 static function getMethodSuffix($method, $params_ary=array()) {
  $c = '__';
  if(is_array($params_ary)){
   foreach($params_ary as $i=>$param){//var_dump($param);
    // Adding special characters to the end of method name 
    switch(gettype($param)){
     case 'array':   $c .= 'a'; break;
     case 'boolean':  $c .= 'b'; break;
     case 'double':   $c .= 'd'; break;
     case 'integer':  $c .= 'i'; break;
     case 'NULL':   $c .= 'n'; break;
     case 'object':
      // Support closure params
      if($param instanceof Closure ){
       $c .= 'c';
      }else{
       $c .= 'o'; 
      }
     break;
     case 'resource':  $c .= 'r'; break;
     case 'string':   $c .= 's'; break;
     case 'unknown type':$c .= 'u'; break;
    }
   }
  }
  return $c;
 }
 // Get a reference variable by name
 static function &refAccess($var_name) {
  $r =& $GLOBALS["$var_name"]; 
  return $r;
 }
}


2) قم باضافة دالة صغيرة لكلاسك الذي ترغب في تفعيل التحميل الزائد به.. هذه الدالة كالتالي:

 function __call($method, $args) {
  return Overloadable::call($this, $method, $args);
 }

الآن شاهد المثال التالي حيث قمت بعمل كلاس باسم Test واضفت في الدالة __call

لاحظ أن php لا تدعم التحميل الزائد لذا يجب عدم عمل دوال بنفس الأسم فمثلاً في كلاس Test تنتهي كل الدوال بشرطتين سفليتين __ ثم حرف أو اكثر يدل على نوع المتغيرات الخاصة بالدالة كالتالي:

لعمل دالة بدون متغيرات :



function myFunction__() {
    // your code
}

اذا نسيت الشرطتين في آخر الدالة فلن يعمل كلاس التحميل الزائد وذلك لأن php ستستدعي الدالة myFunction مباشرة دون استدعاء الدالة __call التي يتم استدعائها في حالة عدم وجود الدالة في الكلاس.

واذا اردت عمل دالة بنفس الاسم مع اضافة متغير رقمي مثلاً تكتب الدالة بالشكل التالي:



function myFunction__i($int) {
    var_dump($int);
}

لاحظ أن حرف i بعد الشرطتين يدل على ان متغير الدالة رقمي integer

ولاضافة دالة بنفس الاسم تحوي متغير نصي تكتب الدالة على النحو الآتي:



function myFunction__s($string) {
   // ...
} 

ولاضافة دالة بأكثر من متغير يكون كالتالي:

function anotherFunction__si($str, $int) {
   echo "str: $str, int: $int";
}

لاحظ ترتيب الأحرف في آخر اسم الدالة بعد الشرطتين يكون بنفس ترتيب متغيرات الدالة..

يمكنك عمل دوال بعدد لا نهائي من المتغيرات..

وهذه قائمة بالأحرف الخاصة بكل نوع من أنواع البيانات التي يمكنك استخدامها:



i: Integer
d: double
s: String
b: Boolean
a: Array
o: Object
c: Closure
r: Resource
n: Null


وهذا كلاس test كاملاً:

class test 
{
 private $name = 'test-1';
 
 // Call Overloadable class 
 // you must copy this method in your class to activate overloading
 function __call($method, $args) {
  return Overloadable::call($this, $method, $args);
 }
 
 // func(closure)
 // New in version 3.8
 function func__c(Closure $callback) {
  $r = pre("func__c(".print_r($callback, 1).");", 'print_r(Closure)', false)."\n";
  $r .= $callback($this->name);
  return $r;
 }
 
 // func(NULL)
 function func__n($null){
  return '[[ NULL ]]';
 }
 
    // myFunction(void)
    function myFunction__() {
        return 'myFunction(void)';
    }
 
    // myFunction(integer)
    function myFunction__i($int) {
        return 'myFunction(integer='.$int.')';
    }
    // myFunction(string)
    function myFunction__s($string) {
        return 'myFunction(string='.$string.')';
    }    
    // myFunction(string)
    function myFunction__so($string, $object) {
        $r = 'myFunction(string='.$string.', object='.get_class($object).')';
  $object->x++;
        $r .= '<pre>Object: ';
        $r .= print_r($object, true);
        $r .= '</pre>';
  return $r;
    }
    // anotherFunction(array)
    function anotherFunction__a($array) {
        $r = 'anotherFunction('.print_r($array, 1).')'."\n";
        $array[0]++;        // change the reference value
        $array['val']++;    // change the reference value
  $r .= 'array[0]='.$array[0]."\n";
  $r .= 'array[val]='.$array['val']."\n";
  return $r;
    }
    // anotherFunction(string, integer)
    function anotherFunction__si($key, $value) {
        $r = 'anotherFunction(string='.$key.', integer='.$value.')';
        // Get a reference
        $a2 =& Overloadable::refAccess($key); // => $a2 =& $GLOBALS['val'];
        $a2 *= 3;   // change the reference value
  $r .= "\nkey=$key, value=$value ($$key * 3) => $$key=$a2;";
  return $r;
    }
}


وهذه دالة لتنسيق المخرجات بسهولة احتاجها دائماً لتنقيح برامجي:

function pre($mixed, $title=null, $print=true){
 $output = "";
 if(empty($mixed)){$output .= "<div><h3>-->Empty $title<--</h3></div>";
  if($print){echo $output; return;}else{return $output;}
 }
 $output .= "<fieldset>";
 if($title){$output .= "<legend><h2>$title</h2></legend>";}
 $output .= '<pre>'. print_r($mixed, true) .'</pre>';
 $output .= "</fieldset>";
 if($print){echo $output;}else{return $output;}
}


الآن طريقة استخدام الكلاس:

//----------------------------------------------------------
// Start
//----------------------------------------------------------
// Some data to work with:
$val  = 10;
class obj {
    public $x=10;
}
//----------------------------------------------------------
// Start
$t = new test;

// Call first method with no args:
pre( $t->myFunction() , 'myFunction()'); 
// Output: myFunction(void)

pre( $t->myFunction($val), 'myFunction__i');
// Output: myFunction(integer=10)

pre( $t->myFunction("hello"), 'myFunction__s');
// Output: myFunction(string=hello)

pre( $t->myFunction("str", new obj()),  'myFunction__so');
/* Output: 
myFunction(string=str, object=obj)
Object: obj Object
(
    [x] => 11
)
*/

//// Passing by Reference:


pre( '$val='.$val,  '$val' );
// Output: $val=10

pre( $t->anotherFunction(array(&$val, 'val'=>&$val)), 'anotherFunction__a' );
// Output:  anotherFunction(Array ( [0] => 10 [val] => 10 ) )
//   array[0]=12
//   array[val]=12

pre( '$val='.$val, '$val' );
// Output: $val=12

pre( $t->anotherFunction('val', $val), 'anotherFunction__si' );
// Output:  anotherFunction(string=val, integer=12)
//    key=val, value=12 ($val * 3) => $val=36;

pre('$val='.$val, '$val');
// Output: $val=36

// Closure example
$f = $t->func( function($n){ return strtoupper($n); } );
/*Output: print_r(Closure)
func__c(Closure Object
(
    [parameter] => Array
        (
            [$n] => 
        )

)
);*/

pre( $f, 'Closure' );
//Output: TEST-1
 pre( $t->func(NULL) , 'Null');
 


كما تلاحظ ارفقت مخرجات كل سطر اسفل منه لكي يتسنى لك فهم الكود، ويمكنك تجربة الكلاس في جهازك والتعديل بما يناسبك..

أي ملاحظة أو استفسار يرجى مراسلتي.



تنزيل المشروع:

https://github.com/hishamdalal/overloadable



الجمعة، 3 يناير 2014

تطبيق لتسهيل عمل تبويبات منسدلة Accordion

حل بالـ $jQuery لعمل تبويبات منسدلة لإظهار وإخفاء المحتوى بالنقر على العنوان..
يقوم هذا التطبيق بتسهيل عملية اظهار وإخفاء المحتوى المتعلق بعنوان معين بسهولة ودون الحاجة لإضافة رقم id لكل عنوان ولكل محتوى،
يمكنك أيضا من تجميع مجموعة تبويبات لإظهارها وإخفاءها معاً ويمكنك من اظهار وإخفاء جميع التبويبات
ويتدبر التطبيق تغيير خلفية العنوان وتغيير الأيقونة التي تدل على فتح أو إغلاق التبويب
أرجو عدم حذف الحقوق:
رابط التحميل: تحميل

الخميس، 26 ديسمبر 2013

فئة لإنشاء صورة والكتابة عليها

اليوم سأشرح لكم فئة/كلاس لإنشاء صورة والكتابة عليها..

كثيرة هي الأمثلة والفئات التي تتعامل مع الصور والنصوص، لكن هذه الفئة تقسم المهام المختلفة لفئات تتخصص كل فئة تقوم بعمل معين لتتكامل الفئات المختلفة مع بعضها..

ملاحظة (لا يشترط ترتيب استخدام الدوال/الوظائف)

اسم الفئة PNGوهي تنشئ صور من النوع png..

نأتي الآن لطريقة الإستخدام:

$png = new PNG();
- انشاء نسخة من الفئة:
$png->size->set(int width, int height, [int quality]);

- تحديد حجم الصورة: وتأخذ المعاملات التالية (العرض، الطول، الجودة:إختياري)

وتتراوح الجودة بين القيمتين= [0-9]

0 : جودة أصلية (بدون ضغط)

1-9: ضغط الصورة (يستهلك الذاكرة إذا كان حجم الصورة كبير)


$png->color->set(int red, int green, int blue);

تحديد اللون: (احمر، اخضر، ازرق)

حيث يتكون اللون من خليط من ثلاثة ألوان رئيسية وتتراوح قيمة اللون الواحد من [0-255]



$png->text->set(int font_size, string text);

- إضافة نص: (حجم الخط، النص)

$png->text->setPos(int x, int y);

تحديد موضع النص: (س، ص)

$png->text->align(boolean horizontal, boolean vertical, [boolean auto_correct]);

توسيط الخط: (افقي، عمودي، تصحيح تلقائي:إختياري)

تستخدم هذه الدالة/الوظيفة لتوسيط الخط في الصورة افقياً أو عمودياً أو كلاهما والمعامل الأخير لتصحيح خطأ صغير في موقع النص.

$png->text->correctPos(int x, int y);

تعديل موقع النص: (س، ص)

يستخدم لازاحة موقع النص ويمكن أن يأخذ قيم سالبة.

إذا كان الخط موسطاً فإنه يضيف القيم في هذه الدالة لإزاحة موضع الخط قليلاً عن الوسط.

$png->text->setAngle(int degree);

تدوير النص: درجة الدوران: [360:0]، [-1:-360]

ومعامل هذه الدالة/الوظيفة يقبل القيم السالبة أيضاً

$png->text->reverse();

قلب النص أو ترتيب مواضع الحروف بالعكس:

يستفاد منه لتصحيح اتجاه الخط العربي (لكن الكلاس لا يدعم اتصال الحروف في اللغة العربية)

$png->text->color->set(int red, int green, int blue);
تحديد لون الخط: (أحمر، اخضر، ازرق)
$png->text->font->set(string font_path.ttf');

تحديد مسار الخط لاستخدام خط معين (مسار الخط)

يجب أن تحدد مسار للخط لاستخدامه وأن يكون من النوع ttf

إذا لم تقم بتحديد مسار الخط فسيتم استخدام خط افتراضي من خطوط النظام لكن حجمه يأخذ قيمة من [1-6] فقط.

$png->execute(string image_path);

تنفيذ الصورة ([مسار الصورة])

إذا وضعت اسم لمسار الصورة فسيتم حفظ الصورة في نفس المسار وسيستبدل الصورة الموجودة..

إذا تركت المعامل فارغاً فسيتم إرجاع سلسة نصية خاصة بالصورة، وقد تم معالجة الملف لكي تظهر الصورة في المتصفح.


يرجى كتابة استفساراتكم في التعليقات..

الكلاس كاملاً في الرابط التالي:

تنزيل التطبيق كاملا


الأحد، 17 نوفمبر 2013

كلاس/فئة لتحويل شكل الروابط CleanURL

السلام عليكم، اقدم لكم اليوم كلاس/فئة لتحويل شكل الروابط، فهناك ما يسمى بـ clean url وهي روابط صديقة لمحركات البحث ويكون بالشكل التالي:

 http://www.site.com/artical/details/231  

بينما الشكل العادي للروابط يكون على النحو التالي:

 http://www.site.com/artical.php?show=details&id=231  

تعريف المتغيرات


 $link->define("
    str show;
    int id;
");  

يجب تعريف متغيرات الرابط التي تستخدمها من خلال الدالة define وذلك لحماية المتغيرات
وتسمح الدالة define بإضافة انواع عديدة لغرض الحماية كل متغير له اسم ونوع فالرابط التالي:

 www.site.com/artical.php?show=details&id=231  

حيث وأن الرابط يحتوي على المتغيرات/المعاملات التالية:
- show متغير نصي
- id  متغير رقمي

اختيار وتغيير شكل الرابط


 $link->setURL('http://www.site.com/?id=231', CleanURL::SHORT);  

تستخدم الدالة setURL لتغيير شكل الرابط ولها ثلاثة معاملات
- الأول تضع فيه الرابط.
- الثاني لتحديد شكل الرابط، وهو يأخذ احدى قيمتين:
* CleanURL::SHORT وهو عبارة عن القيمة 1
* CleanURL::LONG وهو عبارة عن القيمة 2.
- الثالث يستخدم ليقوم بالتحويل قسراً حيث أن الدالة لا تقوم بتحويل أنواع الروابط الخارجية،
ويقتصر على تحويل الروابط الداخلية فقط في حالة عدم إعطاء المعامل الثالث القيمة true.
يجب ان تكون معاملات الرابط الخارجي مشابهة للمعاملات التي تم تعريفها في الدالة define.

تحديد شكل لجميع الروابط اللاحقة


 $link->setType(CleanURL::LONG);  

يمكن استخدام الدالة setType لتحديد شكل جميع الروابط، وتبقى الأولوية للدالة setURL لتحديد شكل الرابط.
وعند استخدام الدالة setType فلا تحتاج لتحديد شكل الرابط في الدالة setURL. استبعاد مسار أو اسم ملف

 $link->exclusionPath( 'forum/thread');  

إذا كان هناك مسار لمجلد معين فيجب تحديده كمسار لكي يتم استبعاده من عملية التحويل، فالرابط التالي:

 http://mysite/forum/thread/512  

يحتوي على مسار

 form/thread  

ويحتوي على متغير

 id=512  

لذا نستخدم الدالة exclusionPath ونحدد المسار المراد استبعاده

 $link->exclusionPath('artical.php', '.php');  

يحتلف تطبيق الدالة exclusionPath على الروابط الطويلة حيث يمكن استبعاد مسار وحذف جزء منه
فمثلاً إذا أردنا تحويل الرابط:

 http://www.site.com/artical.php?show=details&id=231  

ليكون على الشكل :

 www.site.com/artical/details/231  

يجب استبعاد المسار artical.php واستبعاد اللاحقة .php ايضاً لذا نستخدم الدالة exclusionPath.

ملاحظات للتطوير 

بقي التذكير بأنه في حالة رغبتك بتطوير هذا الكلاس تستطيع استخدام الدالتين _short2long و _long2short لتحويل متغيرات الرابط، حيث تقوم كل دالة بتغيير نوع الرابط للشكل المناسب ولاحاجة للتعديل عليهما، وما عدا ذلك فيمكنك تغييره حسب الحاجة.

 كود الكلاس/الفئة CleanURL


<?php

/* ***********************************
 *  Author    : <HishamDalal@gmail.com>
 * Project Name    : CleanURL
 *  Version    : 1.0
 *  Date        : 2013-11-10 13:10
 * *********************************** */

class CleanURL {
    
    const SHORT = 1;
    const LONG = 2;
    // $link_types Would be like this array Ex. array('page'=>1, 'cat'=>'news', 'id'=>23);
    private $link_types = array();
    private $type = 0;
    private $full_url = null;
    private $site_name = null;
    private $exclusion_path = null;
    private $remove_from_path = null;
    
    //------------------------------------------------------------------//
    // This function has an effect that change URL type, 
    //so you don't need to mention the type in second parameter when you use the function "set" 
    function setType($to){
        $to = intval($to);
        if($to == CleanURL::SHORT || $to == CleanURL::LONG){
            $this->type = $to;
        }
    }
    //------------------------------------------------------------------//
    // Used to define URL parameter types
    function define($strCode){
        preg_match_all("/([\w]+)[\s]+([\w]+);/s", $strCode, $m);
        if(isset($m[1]) && isset($m[2])){
            $this->link_types = array_combine($m[2], $m[1]);
        }
    }
    //------------------------------------------------------------------//
    // Make a decision 
    private function _set($link, $type=0) {
    
        if($type==CleanURL::LONG){
            return $this->_short2long($link);
            
        }elseif($type==CleanURL::SHORT){
            return $this->_long2short($link);

        }elseif($this->type==CleanURL::LONG){
            return $this->_short2long($link);
            
        }elseif($this->type==CleanURL::SHORT){
            return $this->_long2short($link);
        }

        return $link;
    }
    //------------------------------------------------------------------//
    private function _short2long($link) {
        //Find wrong sign
        if(strpos($link, '&')){    return $link;    }
        
        $link = trim($link, '/');
        $ary = explode('/', $link);
        if(is_array($ary) && count($ary)>1){
        $i=0;
        $link = '?';
        foreach($this->link_types as $key=>$type){
            $myKey = @$ary[$i];
            if(isset($myKey)){
                $value = $this->_applayVarType($myKey, $type);
                $link .= $key.'='.$value.'&';
            }
            $i++;
        }
        $link = rtrim($link, '&');
        }
        return $link;
    }
    //------------------------------------------------------------------//
    private function _long2short($link1) {
        $link1 = trim($link1, '?');
        $ary = explode('&', $link1);
        $link = '';
        if(is_array($ary) && count($ary)>1){
            foreach($ary as $var) {
                $varData = explode('=', $var);
                if(count($varData)>1){
                    $key = $varData[0];
                    $value = $varData[1]; 
                    if(isset($this->link_types[$key])){
                        $value = $this->_applayVarType($value, $this->link_types[$key]);
                        $link .= $value.'/';
                    }
                }else{
                    return $link1; 
                }
            }
            return rtrim($link, '/');
        }
        return $link1;
    }
    //------------------------------------------------------------------//
    // Secure variable type.
    private function _applayVarType($value, $type) { 
        switch($type) {
            // You can add any security function you want.
            case 'int': $value = intval($value);                            break;
            case 'chr': $value = strlen($value)==1 ? $value : $value[0];    break;
        }
        return $value;
    }
    //------------------------------------------------------------------//
    function exclusionPath($path, $remove=null){
        $this->exclusion_path = $path;//str_replace($remove, '', $path);
        $this->remove_from_path = $remove;
    }
    //------------------------------------------------------------------//
    //------------------------------------------------------------------//
    // Main function for end-user, It's used to convert URL format
    function setURL($url, $type=0, $force=null){

        $parse = parse_url($url);

        if( isset($parse['host']) || $force){
            $scheme = isset($parse['scheme']) ? $parse['scheme'].'//' : '';
            $host     = isset($parse['host']) ? $parse['host'] : '';
            $path     = isset($parse['path']) ? $parse['path'] : '';
            $query     = isset($parse['query']) ? $parse['query'] : '';

            if(@$parse['host']==$_SERVER['HTTP_HOST'] || $force){
                if( $query ){
                    // long to short
                    $path = str_replace($this->exclusion_path, '', $path);
                    $url = $scheme.$host.$path
                        . str_replace($this->remove_from_path, '/', $this->exclusion_path)
                        . $this->_set($query, $type);
                    
                }elseif( $path  ){
                    // short to long
                    $path = str_replace($this->exclusion_path, '', $path);
                    $url = $scheme.$host.'/'
                    .$this->exclusion_path
                    .$this->_set($path, $type);
                    
                }
                $this->exclusion_path = null;
                $this->remove_from_path = null;
            }
        
        }else{
            trigger_error("Wrong URL Format!");
        
        }
        return $url;
        
    }
    //------------------------------------------------------------------//
} 
?>

استخدام الفئة


<?php
 $link = new CleanURL();

// Define parameters types
$link->define("
    int page;
    str cat;
    str sub;
    int id;
    chr k;
");

$url = 'http://localhost/1z/news/details/12/y';
echo '<hr><b>Convert short to long:</b>';
echo '<br /><b>Source:</b> '. $url .'<br /><b>Result:</b> ';
echo $link->setURL($url, CleanURL::LONG);
//------------------------------------------------------------------------

$url = 'http://localhost/?page=1&cat=news&sub=details&id=12code&k=false';
echo '<hr><b>Convert long to short:</b>';
echo '<br /><b>Source:</b> '. $url .'<br /><b>Result:</b> ';
echo $link->setURL($url, CleanURL::SHORT,  true);
//------------------------------------------------------------------------

$link->exclusionPath( 'forum/index.php');
$url = 'http://localhost/forum/index.php/1z/news/details/12/y';
echo '<hr><b>Convert short to long</b> [Use function "exclusionPath()"]: ';
echo '<br /><b>Source:</b> '. $url .'<br /><b>Result:</b> ';
echo $link->setURL($url, CleanURL::LONG);
//------------------------------------------------------------------------

$link->exclusionPath( 'index.php' , '.php');
$url = 'http://localhost/forum/index.php?page=1&cat=news&sub=details&id=12code&k=false';
echo '<hr><b>Convert long to short:</b> [Use function "exclusionPath()"]: ';
echo '<br /><b>Source</b>: '. $url .'<br /><b>Result:</b> ';
echo $link->setURL($url, CleanURL::SHORT);
//------------------------------------------------------------------------

$url = 'http://localhost/1/news/details/12/y';
echo '<hr><b>Convert short to long</b> [Use function "setType()"]: ';
echo '<br /><b>Source:</b> '. $url .'<br /><b>Result:</b> ';
$link->setType(CleanURL::LONG);
echo $link->setURL($url);
//------------------------------------------------------------------------

$url = 'http://othersite.com/any-query';
echo '<hr><b>Convert other site url</b> (Doesn\'t convert): ';
echo '<br /><b>Source</b>: '. $url .'<br /><b>Result:</b> ';
echo $link->setURL($url, CleanURL::LONG);


$url = 'http://othersite.com/forum/?page=1&cat=news&sub=details&id=12code&k=false';
echo '<hr><b>Convert other site url:</b> [Use "force" to convert]: ';
echo '<br /><b>Source</b>: '. $url .'<br /><b>Result:</b> ';
echo $link->setURL($url, CleanURL::SHORT,  true);  
?>
 في حالة وجود خطأ يرجى المشاركة وإيضاح الخطأ ليتم تلافيه، يسعدني قيامكم بتعديل اخطاء الكلاس..

الخميس، 11 أبريل 2013

التحميل الزائد الحقيقي real overload

يبدو أنه لن يهدأ لي بال حتى أحقق التحميل الزائد للغة php بطريقة أكثر وأكثر شبها ببقية اللغات البرمجية..

ستتمكن باستخدام الكلاس overloadable الاصدار v3.1 من استدعاء الدوال بالشكل:

$t->foo();

$t->foo('a');

$t->foo('a', 'b');

$t->foo('a', 2);

$t->foo('s', 2, 9);

$t->foo( array(4,5,6,7) );


كود كلاس overloadable :

/*******************************
 * author  :  hishamdalal@gmail.com 
 * version : 3.1
 * date    : 2013-04-11
 *****************************/

class overloadable
{
 protected $fname = null;
 protected $fargs = array();
 
 //--------------------------------------------------//
 function set($obj, $fname, $args){
  $n = ''; 
  $type = $this->getType($args); 
  $n  = "\$o = new $obj();\n";
  $n .= "if(method_exists(\$o, '$fname"."_$type')){\n";
  $n .= "\t\$r = \$o->$fname"."_$type(". $this->getArgsName($args) .");\n";
  $n .= "}else{\n\t\$r = null;\n";
  $n .= "\ttrigger_error('function ".$fname."_".$type." is not exist!');\n}";
  eval("\$r = $n;");
  return $r;
 }
 //--------------------------------------------------//
 function getType($args) {
  $argType = array();
  foreach($args as $i=>$val) {
   $argType[$i][] = $this->getSuffix($val, $i) ;
  }
  $s = '';
  if(is_array($argType)){
   foreach($argType as $type){
    $s  .= implode('', $type);
   }
   return $s;
  }
  return implode('', $argType);
 } 
 //--------------------------------------------------//
 function getSuffix($byValarg, $i) {
   if( is_numeric($byValarg) ) {
    $type = 'N'; 
    $this->fargs['N'.$i] = $byValarg;
   } elseif( is_array($byValarg) ) {
    $type = 'A';
    $this->fargs['A'.$i] = $byValarg;
   } elseif( is_object($byValarg) ) {
    $type = 'O'; 
    $this->fargs['O'.$i] = $byValarg;
   } elseif( is_resource($byValarg) ) {
    $type = 'R'; 
    $this->fargs['R'.$i] = $byValarg;
   } else {
    $type = 'S'; 
    $this->fargs['S'.$i] = $byValarg;
   } 
   return $type;
 }
 //--------------------------------------------------//
 function getArgsName($args){
  $r = array();
  $ary = array_keys($this->fargs);
  foreach( $ary as $k=>$v){
   $r[]='$this->fargs["'.$v.'"]';
  }
  return implode(", ", $r);
 }
 //--------------------------------------------------// 
 function __call($name, $args){
  $this->fargs = array();
  return $this->set(get_class($this), $name, $args);
 }
 //--------------------------------------------------// 
}

يمكنك الأن بسهولة استخدامه من خلال القيام بالوراثة منه إلى أي كلاس تريد أن تضيف امكانية التحميل الزائد اليه.. مثال لعمل كلاس يقوم بوراثة overloadable ولاحظ كيف تم بناء الدوال بنفس الاسم مع زيادة _ ثم أول حرف من نوع بيانات البراميترات المرسلة:

class test2 extends overloadable {
 function foo_(){
  echo 'foo - no args';
 }
 function foo_S($s){
  echo "foo - one string $s";
 }
 function foo_SS($s1, $s2){
  echo "foo - tow strings $s1, $s2";
 } 
 function foo_SN($s, $n){
  echo "foo - string and number $s, $n";
 }
 function foo_A($ary){
  print_r($ary);
 }
 function foo_AA($ary1, $ary2){
  if(is_array($ary1) && is_array($ary2)){
   echo "foo - tow arrays";
  }else{echo 0;}
 } 
 function foo_O($obj){
  echo "foo - ";
  print_r($obj);
 }
 function hi(){
  echo "hi - welcome!";
 }
}

لاحظ كيف تم بناء الدوال: فالدالة : foo_() لا تحتوي أي باراميتر والدالة foo_S($s) تحتوي متغير نص وهكذا تبني أي دالة ، لكن عند الاستدعاء يجب كتابة اسم الدالة دون شرطة أو رموز فتكتب فقط foo() أو foo('a') كالتالي:

echo '<pre>';
$t = new test2();

echo '< br />foo_: ';
print_r( $t->foo() );

echo '< br />foo_s: ';
print_r( $t->foo('a') );

echo '< br />foo_ss: ';
print_r( $t->foo('a', 'b') );

echo '< br />foo_sn: ';
print_r( $t->foo('a', 2) );

echo '< br />foo_snn: ';
print_r( $t->foo('s', 2, 9) );

echo '< br />foo_a: ';
print_r( $t->foo(array(4,5,6,7)) );

echo '< br />foo_aa: ';
print_r( $t->foo( array(5,6,7), array(8,9,10) ) );

echo '< br />foo_o: ';
print_r( $t->foo($t) );

echo '< br />hi: ';
print_r( $t->hi() );

الأربعاء، 10 أبريل 2013

Class overloadable to make ability for overloading in php كلاس لتمكين التحميل الزائد في php

بعد طول انقطاع أعود للتدوين.. مرحبا بكم :) أبدأ على بركة الله تدوينة جديدة: تحدثت في مقالة سابقة Overloading in php just like C Sharp عن كيفية عمل overload للغة php تشبه الى حد ما خاصية overload في c// الآن اقدم طريقة أحدث، وكود الكلاس كما يلي:

class overloadable 
{ 
 protected $args = array();
 private $argType = array();
 private $argArry = array();
 private $constructArgsAry = array();
 private $method;
 private $className ='';
 
 function setConstructArgs($args) {
  $this->constructArgsAry = $args;
 }
 //--------------------------------------------------//
 function getMethod($className, $method, $args) {
  $this->className = $className;
  
  $this->args = $args;
  $type = $this->getTypes($args);
  
  $method = $method.'_'.$type;
  $this->method = $method; 
  
  return $this->callFunc();
 }
 //--------------------------------------------------//
 function getTypes($args) {
  foreach($args as $i=>$val) {
   $this->argType[$i] = $this->getType($val) ;
  }
  return implode('', $this->argType);
 }
 //--------------------------------------------------//
 function getType($byValarg) {
   if( is_numeric($byValarg) ) {
    $type = 'N'; //'numeric';
   } elseif( is_array($byValarg) ) {
    $type = 'A'; //'array';
   } elseif( is_object($byValarg) ) {
    $type = 'O'; //'object';
   } elseif( is_resource($byValarg) ) {
    $type = 'R'; //'resource';
   } else {
    $type = 'S'; //'string';
   } 
   return $type;
 }
 //--------------------------------------------------//
 function callFunc() {
  $className = $this->className;
  $method = $this->method;
  
  $constr_argsStringKeys='';

  $num_args = count($this->args);
  $argsAry = array();
  if($num_args>0){
   
   for($i=0; $i<$num_args; $i++) {
    $argsAry['$arg_'.$i] = $this->args[$i];
    eval("\$arg_$i = \$this->args[$i];");
   }
   $argsStringKeys = implode(', ', array_keys($argsAry));

   $func = create_function($argsStringKeys, 
      '$d = new '.$className.'('
      . $constr_argsStringKeys .'); return $d->'
      . $method.'('.$argsStringKeys.');');
   
   eval("\$f = \$func($argsStringKeys);"); 
   return $f;
  } 
 }
}

طريقة الاستخدام : يجب أن تقوم بعمل وراثة من الكلاس overloadable يجب اضافة كود معين للدالة التي لا تحتوي على أي براميتر. ثم اضافة دوال أخرى بنفس الاسم ولكن يضاف في نهاية اسم الدالة شرطة مائلة _ ثم أول حرف من نوع المتغير فمثلا: الدالة hi_s تعني أن هذه الدالة لها براميتر واحد نصي الدالة hi_sa تعني ان هذه الدالة لها براميترين واحد نصي والثاني مصفوفة. مثلاً يتم بناء كلاس وليكن اسمه myClass:

class myClass extends overloadable 
{
 function hi() {
  // important to work other methods
  $r = parent::getMethod(__CLASS__, __FUNCTION__, func_get_args());
  if($r){ return $r; }
  // code for method hi();
  return 'hi!';
 }
 function hi_s($name){
  return "Hi $name";
 }
 function hi_ss($var1, $var2){
  return "Hi $var1 $var2";
 }
 function hi_sa($name, $ary){
  $r = $name.' have ';
  foreach($ary as $thing){
   $r .= "$thing and ";
  }
  return rtrim($r, 'and ') .'.';
 }
 
 function hi_aa($ary1, $ary2){
  return 'Ary1: '. print_r($ary1, 1).' < br />ARY2:'. print_r($ary2, 1);
 }
 
 function wins(){
  $r = parent::getMethod(__CLASS__, __FUNCTION__, func_get_args());
  if($r){ return $r; }
  return 'You are the winner!';
 }
 
 function wins_sn($wining, $cash){
  return $wining.' wins '. $cash .'$';
 }
}

مثال على استخدام الكلاس myClass:

$o = new myClass();

echo '<pre>';
print_r( $o->hi() );
echo '< br />';
print_r( $o->hi('saleem', array('a job', 'a car', 'a house') ) );
echo '< br />';
print_r( $o->hi('Hishahm', 'Dalal') );
echo '< br />';
print_r( $o->hi(array(1,2), array('a','b') ) );
echo '< br />';
print_r( $o->wins('Hisahm', 1000) );
echo '< br />';
print_r( $o->wins() );

لتحميل المثال كاملا انقر هنا

الأحد، 27 نوفمبر 2011

Overloading in php just like C Sharp

كيف تحصل على التحميل الزائد بشكل أكثر شبها بلغة c#
ففي لغة C# يمكننا عمل ما يلي:
// author: hishamdalal@gmail.com 2011
class person
{
    private int ID;
    private string Name;

    public void Add(string ID, string Name)
    {
        this.ID = Convert.ToInt32(ID);
        this.Name = Name;
    }
    public person()
    {
        this.Add("0", "no name!");
    }
    public person(string ID, string Name)
    {
        this.Add(ID, Name);
    }
}

students s = new students();
s.person();             // method without args
s.person(1, "hisham");  // overload method with args

فكيف يمكننا فعل ذلك بواسطة php?

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Blogger Templates | تعريب وتطوير : قوالب بلوجر معربة