Организация репозитории ф-ций проекта

LanKing

Guest
Организация репозитории ф-ций проекта

Приветствую, многоуважаемый all.

Требуется помощь в следующем вопросе.

На настоящий момент в нашей библиотеке custom functions насчитывается более 1000 ф-ций, сортированных по пакетам. К примеру - пакеты - syntaxvalidate, arrays, strings и т.п.

Хотелось бы:
1. Организовать удобный репозиторий, чтобы в процессе разработки наши программисты могли использовать любые ф-ции из репозитория.
2. При финальной прогонке проекта перед сдачей в директорию репозитория сдаваемого проекта копировались бы только те ф-ции, которые задействованы в проекте.
3. Чтобы для реализации первых двух пунктов применялось бы минимум телодвижений.

Был предложен следующий метод (по аналогии с smarty functions)
Организация репозитория вида
/repository/$package/function.$name.inc
/repository/$package/class.$name.inc

Организация вызова ф-ции через:

Function TakeFunc ($package, $name) {
if (!isset ($package)) { echo 'Function package parameter is not defined'; return; }
if (!isset ($name)) { echo 'Function name parameter is not defined'; return; }

$funcname='function_'.$package.'_'.$name;

require_once ('/repository/'.$package.'/function.'.$name.'.lib');
$args_list=func_get_args(); unset ($args_list[0]); unset ($args_list[1]);

$args=''; $separator=''; foreach ($args_list as $param) { $args.="$separator'$param'"; $separator=', '; }


$funcreturn=call_user_func ($funcname, $args);

return $funcreturn;
}


И при финальной прогонке проекта перед сдачей какимм-то отдельным парсером вылавливать TakeFunc в файлах кода.

Решение мне не очень нравится, кто-нибудь предложит что-то более удобное ? Напомниаю, основа - макс. автоматизированность. Человеческий фактор не идеален.
 

[DAN]

Старожил PHPClub
Максимальная автоматизированность - это PHP5, библиотека классов и __autoload().

В Вашем случае первое, что приходит в голову, это отслеживание ошибки при вызове неподключенной функции и ее подключение в обработчике ошибок.
 

gfd

Guest
Я думаю можно упростить Ваше решение:

не использовать TakeFunc и организовать структуру репозитория просто /rep/$pack

в процессе создания проекта включать весь репозиторий,
а для выдачи финальной версии использовать скрипт, который составит список всех ф-й из репозитория с указанием пакетов, где найдены, определит какие из них исп в кодах проекта и создаст репозиторий того же вида, что и основной но с исп только нужных пакетов и содерж только нужные функции.

конечно, если ф-и называть, например, rep_$pack_$funcname
все это можно оптимизировать, но если ф-и названы не по подобным правилам, я считаю - ничего страшного, ведь этот процесс будет запускаться не при каждом старте скриптов проэкта, а один раз (в идеале :) ).

Решение "тупо и в лоб" зато полная автоматизация :) .
 

vitus

мимо проходил
а это реально нужно - именно на уровне функции/класса подключать?
может лучше файлы цеплять?

тогда можно подменить require_once() на свою конструкцию типа import(), которая будет при deploy=0 искать сначала в lib проекта, потом в репозитории.
при установке deploy=1 в конфиге, пусть она скопирует нужные файлы в lib проекта, потом deploy=0; repo=lib;
 

striimii

Guest
А для функций такая полезная вещица аля __autoload есть? Полистал мануал, не нашел.

Имеется в виду, отлов попыток обращения к 'undefined functions'.
Ведь в error_handler невозможно (без извращений с ob_start) продолжить работу после такой ошибки. PHP увренно останавливает выполнение.
 

valyala

Новичок
А для функций такая полезная вещица аля __autoload есть? Полистал мануал, не нашел.

Имеется в виду, отлов попыток обращения к 'undefined functions'.
Ведь в error_handler невозможно (без извращений с ob_start) продолжить работу после такой ошибки. PHP увренно останавливает выполнение.
Ниже приведен класс автоматической загрузки функций, предназначенный для PHP5. Но ничто не мешает создать аналогичный для PHP4 - нужно лишь воспользоваться overload() http://php.net/overload , изменить имя конструктора и немного подправить метод __call() - в PHP4 возвращаемое функцией значение передается как ссылка в третьем параметре.

PHP:
/**
   Класс DynLoader позволяет использовать большие
   библиотеки функций, размещенные в различных папках.
   при этом запрашиваемые функции загружаются динамически,
   тем самым экономится время, затрачиваемое на парсинг
   больших библиотек, содержащих много функций

   Пример использования этого класса.

   Допустим, у нас есть две библиотеки функций lib1.php и lib2.php, каждая
   из которых содержит кучу функций. При этом скрипты, подключающие эти
   библиотеки, используют лишь незначительную часть функций.
   Мы можем разбить библиотеки lib1.php и lib2.php на отдельные функции
   и поместить их в отдельные файлы в каталогах /php_libs/lib1 и
   /php_libs/lib2 соответственно.

   Тогда, вместо того, чтобы подключать lib1.php и lib2.php,
   мы можем воспользоваться DynLoader, который будет подключать только
   те функции из библиотек, которые используются в текущем скрипте.

   Было:
   // две библиотеки, содержащие кучу полезных функций
   // и поэтому долго загружающиеся
   include('lib1.php');
   include('lib2.php');

   Стало:
   include('dyn_loader.php');
   $lib1 = new DynLoader('/php_libs/lib1');
   $lib2 = new DynLoader('/php_libs/lib2');

   // вызываем функцию f1() из библиотеки lib1
   // эта функция подгружается динамически из файла f1.inc.php, находящегося
   // в каталоге /php_libs/lib1 , а затем вызывается
   $lib1->f1();

   Разрешение конфликта имен:
   Для этого предусмотрен второй параметр в конструкторе DynLoader.
   Например, у нас есть две библиотеки с одноименными функциями
   f1() и мы хотим иметь возможность пользоваться ими в одном скрипте.
   Тогда можно поступить следующим образом:
       - добавить префикс lib1_ и lib2_ в начало имени функций, принадлежащих
       библиотекам lib1 и lib2 соответственно
       - передать строки 'lib1_' и 'lib2_' в качестве второго параметра
         при создании объектов класса DynLoader для работы с библиотеками
         функций:
           $lib1 = new DynLoader('/php_libs/lib1', 'lib1_');
           $lib2 = new DynLoader('/php_libs/lib2', 'lib2_');
       - свободно вызывать функции с одинаковыми именами из разных библиотек:
           $lib1->f1(); // вызов f1() из библиотеки lib1
           $lib2->f1(); // вызов f1() из библиотеки lib2

   Если вам не нравится расширение 'inc.php' для файлов, содержащих функции,
   вы можете использовать другое расширение. В этом случае, при создании
   объекта DynLoader укажите в качестве третьего параметра желаемое расширение.
   Например, файлы, содержащие функции, имеют расширение 'php'. Тогда создание
   объекта может выглядеть следующим образом (отсутствует префикс функций):
       $lib1 = new DynLoader('/php_libs/lib1', '', 'php');

   Известные баги:
       класс DynLoader не умеет передавать параметры в функции по ссылке.
       Например, если в библиотеке присутствует такая функция:
           function f1(&$a) { $a++; }
       то при вызове ее через DynLoader значение переданного в нее параметра
       не увеличится, т.к. оно будет передано по значению, а не по ссылке.
*/
class DynLoader
{
   private $func_dir; // каталог, в котором находятся функции
   private $func_prefix; // префикс функций
   private $file_ext; // расширение файлов, в которых находятся функции

   public function __construct($func_dir = '.', $func_prefix = '', $file_ext = 'inc.php')
   {
       if (!is_dir($func_dir)) {
           exit("cannot find directory [{$func_dir}]");
       }

       $this->func_dir = realpath($func_dir);
       $this->func_prefix = $func_prefix;
       $this->file_ext = $file_ext;
   }

   public function __call($func, $params)
   {
       $func_name = $this->func_prefix . $func;
       if (!function_exists($func_name)) {
           // пытаемся загрузить файл с функцией из каталога $func_dir
           $filename = $this->func_dir . '/' . $func . '.' . $this->file_ext;
           if (!is_file($filename)) {
               exit("cannot find file [{$filename}] for function [{$func}]");
           }
           require_once($filename);
           if (!function_exists($func_name)) {
               exit("cannot find function [{$func}] in file [{$filename}]");
           }
       }
       // вызываем функцию и возвращаем результат выполнения
       return call_user_func_array($func_name, $params);
   }
}
 

Screjet

Новичок
Как вариант: запускаете дебаг, с которым работает простенький скриптик по отлову вызова ф-ций.
Выполнили 1 запрос (последовательность зап.) : получили список вызовов, записали.
Выполнили n запрос ...
Запускаем примитивную грепалку, которая выдергивает из кучи скриптов необходимые ф-ции и записывает в файлики, согласно полученных списков вызовов запросов (посл.).
 
Сверху