Это связано с требованием отдельной компиляции и потому, что шаблоны являются полиморфизмом типа создания экземпляров.
Давайте немного приблизимся к конкретному для объяснения. Скажем, у меня есть следующие файлы:
class MyClass<T>
class MyClass<T>
MyClass<int>
. Отдельное средство компиляции. Я должен скомпилировать foo.cpp независимо от bar.cpp. Компилятор полностью выполняет всю сложную работу по анализу, оптимизации и генерации кода на каждом модуле компиляции; нам не нужно анализировать целую программу. Только компоновщик должен обрабатывать всю программу одновременно, и задача компоновщика значительно упрощается.
bar.cpp даже не нужно существовать при компиляции foo.cpp, но я все равно должен быть в состоянии связать foo.o Я уже имел вместе с bar.o Я только что выпустил, не перекомпилируя foo.cpp. foo.cpp может даже быть скомпилирован в динамическую библиотеку, распределенную где-то в другом месте без foo.cpp, и связан с кодом, который они пишут спустя годы после того, как я написал foo.cpp.
«Полиморфизм в стиле объектов» означает, что template MyClass<T>
не является общим классом, который может быть скомпилирован в код, который может работать для любого значения T
. Это добавит накладные расходы, такие как бокс, необходимо передать указатели на функции для распределителей и конструкторов и т. Д. Намерение шаблонов C ++ состоит в том, чтобы избежать необходимости писать почти идентичные class MyClass_int
, class MyClass_float
и т. Д., Но все же быть в состоянии закончить с компилируемым кодом, который в основном выглядит так, как если бы мы имели каждую версию отдельно. Таким образом, шаблон является буквально шаблоном; шаблон класса не класс, это рецепт создания нового класса для каждого T
, с которым мы сталкиваемся. Шаблон не может быть скомпилирован в код, только результат создания экземпляра шаблона может быть скомпилирован.
Итак, когда foo.cpp скомпилирован, компилятор не может видеть bar.cpp, чтобы знать, что MyClass<int>
необходимо. Он может видеть шаблон MyClass<T>
, но он не может испускать код для этого (это шаблон, а не класс). И когда компилируется bar.cpp, компилятор может видеть, что ему нужно создать MyClass<int>
, но он не может видеть шаблон MyClass<T>
(только его интерфейс в foo.h), поэтому он не может его создать.
Если foo.cpp сам использует MyClass<int>
, тогда код для него будет сгенерирован при компиляции foo.cpp, поэтому, когда bar.o связан с foo.o, они могут быть подключены и будут работать. Мы можем использовать этот факт, чтобы позволить конечный набор экземпляров шаблонов быть реализован в .cpp-файле, написав один шаблон. Но bar.cpp не может использовать шаблон в качестве шаблона и создавать его на всех типах, которые ему нравятся; он может использовать только ранее существовавшие версии шаблона, которые автор foo.cpp думал предоставить.
Вы можете подумать, что при компиляции шаблона компилятор должен «сгенерировать все версии», с теми, которые никогда не используются, отфильтровываются во время связывания. Помимо огромных накладных расходов и экстремальных трудностей, с которыми сталкивался такой подход, поскольку «модификаторы типа», такие как указатели и массивы, позволяют даже встроенным типам создавать бесконечное количество типов, что происходит, когда я расширяю свою программу добавив:
class BazPrivate
и использует MyClass<BazPrivate>
Невозможно, чтобы это могло работать, если мы либо
MyClass<T>
MyClass<T>
, чтобы компилятор мог генерировать MyClass<BazPrivate>
во время компиляции baz.cpp. Никто не любит (1), потому что системы компиляции целых программ принимают forever для компиляции и потому что это делает невозможным распространение компилированных библиотек без исходного кода. Итак, у нас есть (2).
Вы можете получить вот так:
$this->input->get('some_variable', TRUE);
Если вы хотите, чтобы не разобрать строку запроса:
$this->input->server('QUERY_STRING');
Вы можете создать правило в вашем .htaccess, чтобы предотвратить обстрел MOD_REWRITE на этой конкретной странице. Это позволит вам использовать _GET.
Откройте application / config / config.php и установите следующие значения:
$config['uri_protocol'] = "PATH_INFO";
$config['enable_query_strings'] = TRUE;
Теперь строки запроса должны работать нормально.
Я использую CodeIgniter уже больше года. По большей части мне это очень нравится (я участвую в форуме и использую его во всех случаях, когда могу), но я НЕНАВИЖУ ГОРДЕННОСТЬ этого утверждения в руководстве:
Уничтожает глобальный массив GET. Поскольку CodeIgniter не использует строки GET , нет причин разрешать это.
Предположение, что вам никогда не понадобится GET в приложении CodeIgniter, бессмысленно! Уже через несколько дней мне пришлось иметь дело с обратными страницами из PayPal и ClickBank (я уверен, что есть миллион других). Угадайте, что они используют GET !!!
Есть способы остановить это раздавливание GET, но они имеют тенденцию портить другие вещи. Чего вы не хотите слышать, так это того, что вам нужно перекодировать все свои представления, потому что вы включили строки запроса, а теперь ваши ссылки не работают! Внимательно прочтите руководство по этой опции!
Один, который мне нравится (но не сработал, потому что установка REQUEST_URI в config.php сломала мой сайт), расширяет класс Input:
class MY_Input extends CI_Input
{
function _sanitize_globals()
{
$this->allow_get_array = TRUE;
parent::_sanitize_globals();
}
}
Но лучший серьезный способ - протестировать с помощью print_r ($ _ SERVER) на URL-адрес, по которому вам нужны переменные GET. Посмотрите, какая опция протокола URI показывает ваши переменные GET, и используйте ее.
В моем случае я вижу, что мне нужно, в REQUEST_URI
// defeat stupid CI GET squashing!
parse_str($_SERVER['REQUEST_URI'], $_GET);
. Это возвращает строку запроса в суперглобальный объект $ _GET для этого экземпляра страницы (вам не нужно использовать $ _GET, это может быть любая переменная.)
EDIT
После публикации этого сообщения я обнаружил, что при использовании REQUEST_URI вы потеряете свой первый ключ массива строки запроса, если не удалите все, что находится перед?. Например, URL-адрес типа / controller / method? One = 1 & two = 2 заполнит массив $ _GET в этом примере массивом ('method? One' => 1, 'two' => 2). Чтобы обойти это, я использовал следующий код:
parse_str(substr(strrchr($_SERVER['REQUEST_URI'], "?"), 1), $_GET);
Полагаю, мне следовало предоставить пример, поэтому здесь:
class Pgate extends Controller {
function postback() {
parse_str(substr(strrchr($_SERVER['REQUEST_URI'], "?"), 1), $_GET);
$receipt = $this->input->xss_clean($_GET['receipt']);
}
}
Вы можете создать ловушку pre_system. В создаваемом вами классе перехвата вы можете получить нужные параметры запроса и добавить их в $ _POST для нормальной обработки CI. Я сделал это для помощника jQuery Ajax.
Например:
(Назовите этот файл autocomplete.php или как угодно, что вы указали в качестве имени файла в ловушке)
<?php
/*
By Brodie Hodges, Oct. 22, 2009.
*/
if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* Make sure this file is placed in your application/hooks/ folder.
*
* jQuery autocomplete plugin uses query string. Autocomplete class slightly modified from excellent blog post here:
* http://czetsuya-tech.blogspot.com/2009/08/allowing-url-query-string-in.html
* Ajax autocomplete requires a pre_system hook to function correctly. Add to your
* application/config/hooks.php if not already there:
$hook['pre_system'][] = array(
'class' => 'Autocomplete',
'function' => 'override_get',
'filename' => 'autocomplete.php',
'filepath' => 'hooks',
'params' => array()
);
*
*
*/
class Autocomplete {
function override_get() {
if (strlen($_SERVER['QUERY_STRING']) > 0) {
$temp = @array();
parse_str($_SERVER['QUERY_STRING'], $temp);
if (array_key_exists('q', $temp) && array_key_exists('limit', $temp) && array_key_exists('timestamp', $temp)) {
$_POST['q'] = $temp['q'];
$_POST['limit'] = $temp['limit'];
$_POST['timestamp'] = $temp['timestamp'];
$_SERVER['QUERY_STRING'] = "";
$_SERVER['REDIRECT_QUERY_STRING'] = "";
$_GET = @array();
$url = strpos($_SERVER['REQUEST_URI'], '?');
if ($url > -1) {
$_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 0, $url);
}
}
}
}
}
?>
Спасибо всем другим плакатам. Вот что пришло мне в голову:
$qs = $_SERVER['QUERY_STRING'];
$ru = $_SERVER['REQUEST_URI'];
$pp = substr($ru, strlen($qs)+1);
parse_str($pp, $_GET);
echo "<pre>";
print_r($_GET);
echo "</pre>";
То есть, теперь я мог делать:
$token = $_GET['token'];
В .htaccess мне пришлось изменить:
RewriteRule ^(.*)$ /index.php/$1 [L]
на:
RewriteRule ^(.*)$ /index.php?/$1 [L]
Если вы используете mod_rewrite для удаления файла index.php, вы можете использовать следующий код для получения переменных GET (через $ this-> input-> get ()). Предполагая конфигурацию по умолчанию, назовите файл MY_Input.php и поместите его в каталог приложений / библиотек.
Использование: $ this-> input-> get ()
class MY_Input extends CI_Input {
function My_Input()
{
parent::CI_Input();
// allow GET variables if using mod_rewrite to remove index.php
$CFG =& load_class('Config');
if ($CFG->item('index_page') === "" && $this->allow_get_array === FALSE)
{
$_GET = $this->_get_array();
}
}
/**
* Fetch an item from the GET array
*
* @param string $index
* @param bool $xss_clean
*/
function get($index = FALSE, $xss_clean = FALSE)
{
// get value for supplied key
if ($index != FALSE)
{
if (array_key_exists(strval($index), $_GET))
{
// apply xss filtering to value
return ($xss_clean == TRUE) ? $this->xss_clean($_GET[$index]) : $_GET[$index];
}
}
return FALSE;
}
/**
* Helper function
* Returns GET array by parsing REQUEST_URI
*
* @return array
*/
function _get_array()
{
// retrieve request uri
$request_uri = $this->server('REQUEST_URI');
// find query string separator (?)
$separator = strpos($request_uri, '?');
if ($separator === FALSE)
{
return FALSE;
}
// extract query string from request uri
$query_string = substr($request_uri, $separator + 1);
// parse query string and store variables in array
$get = array();
parse_str($query_string, $get);
// apply xss filtering according to config setting
if ($this->use_xss_clean === TRUE)
{
$get = $this->xss_clean($get);
}
// return GET array, FALSE if empty
return (!empty($get)) ? $get : FALSE;
}
}